[llvm] [Instsimplify] lshr&icmp adds support for the or instruction (PR #69445)

via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 18 03:51:18 PDT 2023


https://github.com/DianQK created https://github.com/llvm/llvm-project/pull/69445

Closes #69333.

>From 8664b9332743338dda52d0f30cb68acaa6117264 Mon Sep 17 00:00:00 2001
From: DianQK <dianqk at dianqk.net>
Date: Wed, 18 Oct 2023 08:05:41 +0800
Subject: [PATCH 1/3] [InstSimplify] Pre-commit tests for lshr&or

---
 llvm/test/Transforms/InstSimplify/compare.ll | 142 +++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index ac2ebf52ed6296e..9e80fa7ba4e93f2 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -565,6 +565,148 @@ define i1 @lshr7(i32 %X, i32 %Y) {
   ret i1 %C
 }
 
+define i1 @or_lshr1(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @or_lshr1(
+; CHECK-NEXT:    [[A:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = lshr i32 %X, %Y
+  %B = or i32 %X, %Z
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_lshr2(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @or_lshr2(
+; CHECK-NEXT:    [[A:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[Y]], [[Z:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = lshr i32 %X, %Y
+  %B = or i32 %Y, %Z
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_lshr3(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
+; CHECK-LABEL: @or_lshr3(
+; CHECK-NEXT:    [[A:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B0:%.*]] = or i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[B0]], [[Z1:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = lshr i32 %X, %Y
+  %B0 = or i32 %X, %Z
+  %B = or i32 %B0, %Z1
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_lshr4(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
+; CHECK-LABEL: @or_lshr4(
+; CHECK-NEXT:    [[A:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B0:%.*]] = or i32 [[Y]], [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[B0]], [[Z1:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = lshr i32 %X, %Y
+  %B0 = or i32 %Y, %Z
+  %B = or i32 %B0, %Z1
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_lshr5(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
+; CHECK-LABEL: @or_lshr5(
+; CHECK-NEXT:    [[A:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B0:%.*]] = or i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = and i32 [[B0]], [[Z1:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = lshr i32 %X, %Y
+  %B0 = or i32 %X, %Z
+  %B = and i32 %B0, %Z1
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_udiv1(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @or_udiv1(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = udiv i32 %X, %Y
+  %B = or i32 %X, %Z
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_udiv2(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @or_udiv2(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[Y]], [[Z:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = udiv i32 %X, %Y
+  %B = or i32 %Y, %Z
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_udiv3(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
+; CHECK-LABEL: @or_udiv3(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B0:%.*]] = or i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[B0]], [[Z1:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = udiv i32 %X, %Y
+  %B0 = or i32 %X, %Z
+  %B = or i32 %B0, %Z1
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_udiv4(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
+; CHECK-LABEL: @or_udiv4(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B0:%.*]] = or i32 [[Y]], [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[B0]], [[Z1:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = udiv i32 %X, %Y
+  %B0 = or i32 %Y, %Z
+  %B = or i32 %B0, %Z1
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
+define i1 @or_udiv5(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
+; CHECK-LABEL: @or_udiv5(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B0:%.*]] = or i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = and i32 [[B0]], [[Z1:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = udiv i32 %X, %Y
+  %B0 = or i32 %X, %Z
+  %B = and i32 %B0, %Z1
+  %C = icmp ult i32 %B, %A
+  ret i1 %C
+}
+
 define i1 @lshr_nonzero_eq(i32 %x) {
 ; CHECK-LABEL: @lshr_nonzero_eq(
 ; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0

>From e043dda644d08a798f81a547d829cf9d13cb629d Mon Sep 17 00:00:00 2001
From: DianQK <dianqk at dianqk.net>
Date: Wed, 18 Oct 2023 08:18:07 +0800
Subject: [PATCH 2/3] [InstSimplify] x >>u y <=u x | z --> true

---
 llvm/lib/Analysis/InstructionSimplify.cpp    | 27 +++++++++++++++-----
 llvm/test/Transforms/InstSimplify/compare.ll | 10 ++------
 2 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index b3feb2470e58efd..7701e157172a1e9 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3174,16 +3174,29 @@ static Value *simplifyICmpWithBinOpOnLHS(CmpInst::Predicate Pred,
   }
 
   // x >>u y <=u x --> true.
+  // x >>u y <=u x | z --> true.
   // x >>u y >u  x --> false.
+  // x >>u y >u  x | z --> false.
   // x udiv y <=u x --> true.
+  // x udiv y <=u x | z --> true.
   // x udiv y >u  x --> false.
-  if (match(LBO, m_LShr(m_Specific(RHS), m_Value())) ||
-      match(LBO, m_UDiv(m_Specific(RHS), m_Value()))) {
-    // icmp pred (X op Y), X
-    if (Pred == ICmpInst::ICMP_UGT)
-      return getFalse(ITy);
-    if (Pred == ICmpInst::ICMP_ULE)
-      return getTrue(ITy);
+  // x udiv y >u  x | z --> false.
+  const Value *RHS0;
+  if (match(LBO, m_LShr(m_Value(RHS0), m_Value())) ||
+      match(LBO, m_UDiv(m_Value(RHS0), m_Value()))) {
+    const Value *RHS1;
+    const Value *RHS2;
+    // TODO: We can handle multiple and instructions.
+    if (RHS0 == RHS || (match(RHS, m_Or(m_Value(RHS1), m_Value(RHS2))) &&
+                        (RHS1 == RHS0 || RHS2 == RHS0))) {
+      // icmp pred (X op Y), X
+      if (Pred == ICmpInst::ICMP_UGT) {
+        return getFalse(ITy);
+      }
+      if (Pred == ICmpInst::ICMP_ULE) {
+        return getTrue(ITy);
+      }
+    }
   }
 
   // If x is nonzero:
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index 9e80fa7ba4e93f2..43dbe2a94e1fd3b 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -567,10 +567,7 @@ define i1 @lshr7(i32 %X, i32 %Y) {
 
 define i1 @or_lshr1(i32 %X, i32 %Y, i32 %Z) {
 ; CHECK-LABEL: @or_lshr1(
-; CHECK-NEXT:    [[A:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[B:%.*]] = or i32 [[X]], [[Z:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 false
 ;
   %A = lshr i32 %X, %Y
   %B = or i32 %X, %Z
@@ -638,10 +635,7 @@ define i1 @or_lshr5(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
 
 define i1 @or_udiv1(i32 %X, i32 %Y, i32 %Z) {
 ; CHECK-LABEL: @or_udiv1(
-; CHECK-NEXT:    [[A:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[B:%.*]] = or i32 [[X]], [[Z:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 false
 ;
   %A = udiv i32 %X, %Y
   %B = or i32 %X, %Z

>From 0f7fb8655d30dce926ee514635768b57eabe5bda Mon Sep 17 00:00:00 2001
From: DianQK <dianqk at dianqk.net>
Date: Wed, 18 Oct 2023 08:36:26 +0800
Subject: [PATCH 3/3] [InstSimplify] x >>u y <=u x | z1 | z2 | ... --> true

---
 llvm/lib/Analysis/InstructionSimplify.cpp    | 23 +++++++++++++++-----
 llvm/test/Transforms/InstSimplify/compare.ll | 12 ++--------
 2 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 7701e157172a1e9..1665d6d63ab6e34 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3103,6 +3103,23 @@ static Value *simplifyICmpWithConstant(CmpInst::Predicate Pred, Value *LHS,
   return nullptr;
 }
 
+static bool existOrChain(const Value *From, const Value *To) {
+  const Value *LVal;
+  const Value *RVal;
+  SmallVector<const Value *, 10> WorkList;
+  WorkList.push_back(From);
+  while (!WorkList.empty() && WorkList.size() < 16) {
+    From = WorkList.pop_back_val();
+    if (match(From, m_Or(m_Value(LVal), m_Value(RVal)))) {
+      if (LVal == To || RVal == To)
+        return true;
+      WorkList.push_back(LVal);
+      WorkList.push_back(RVal);
+    }
+  }
+  return false;
+}
+
 static Value *simplifyICmpWithBinOpOnLHS(CmpInst::Predicate Pred,
                                          BinaryOperator *LBO, Value *RHS,
                                          const SimplifyQuery &Q,
@@ -3184,11 +3201,7 @@ static Value *simplifyICmpWithBinOpOnLHS(CmpInst::Predicate Pred,
   const Value *RHS0;
   if (match(LBO, m_LShr(m_Value(RHS0), m_Value())) ||
       match(LBO, m_UDiv(m_Value(RHS0), m_Value()))) {
-    const Value *RHS1;
-    const Value *RHS2;
-    // TODO: We can handle multiple and instructions.
-    if (RHS0 == RHS || (match(RHS, m_Or(m_Value(RHS1), m_Value(RHS2))) &&
-                        (RHS1 == RHS0 || RHS2 == RHS0))) {
+    if (RHS0 == RHS || existOrChain(RHS, RHS0)) {
       // icmp pred (X op Y), X
       if (Pred == ICmpInst::ICMP_UGT) {
         return getFalse(ITy);
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index 43dbe2a94e1fd3b..75c9a69b26245d4 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -590,11 +590,7 @@ define i1 @or_lshr2(i32 %X, i32 %Y, i32 %Z) {
 
 define i1 @or_lshr3(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
 ; CHECK-LABEL: @or_lshr3(
-; CHECK-NEXT:    [[A:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[B0:%.*]] = or i32 [[X]], [[Z:%.*]]
-; CHECK-NEXT:    [[B:%.*]] = or i32 [[B0]], [[Z1:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 false
 ;
   %A = lshr i32 %X, %Y
   %B0 = or i32 %X, %Z
@@ -658,11 +654,7 @@ define i1 @or_udiv2(i32 %X, i32 %Y, i32 %Z) {
 
 define i1 @or_udiv3(i32 %X, i32 %Y, i32 %Z, i32 %Z1) {
 ; CHECK-LABEL: @or_udiv3(
-; CHECK-NEXT:    [[A:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[B0:%.*]] = or i32 [[X]], [[Z:%.*]]
-; CHECK-NEXT:    [[B:%.*]] = or i32 [[B0]], [[Z1:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[B]], [[A]]
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 false
 ;
   %A = udiv i32 %X, %Y
   %B0 = or i32 %X, %Z



More information about the llvm-commits mailing list