[llvm] [ValueTracking] Analyze `Select` in `isKnownNonEqual`. (PR #68427)

Mikhail Gudim via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 10 10:21:38 PDT 2023


https://github.com/mgudim updated https://github.com/llvm/llvm-project/pull/68427

>From edf1e40f05162d5403ffc11bf5e1cb925aa41efa Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 3 Oct 2023 11:56:50 -0400
Subject: [PATCH 1/5] [ValueTracking] Analyze `Select` in `isKnownNonEqual`.

Basic way to recursively analyze `select` in `isKnownNonEqual`: `select %c, %t, %f` is
non-equal to `%x` if `%t` is non-equal to `%x` and `%f` is non-equal to
`%x`.
---
 llvm/lib/Analysis/ValueTracking.cpp           | 20 +++++++++++
 .../test/Analysis/BasicAA/non-equal-select.ll | 33 +++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 llvm/test/Analysis/BasicAA/non-equal-select.ll

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 3af5a6d9a167de4..1c284e8d85ca417 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3112,6 +3112,23 @@ static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2,
   return true;
 }
 
+static bool isNonEqualSELECT(const Value *V1, const Value *V2, unsigned Depth,
+                             const SimplifyQuery &Q) {
+  const SelectInst *SI1 = dyn_cast<SelectInst>(V1);
+  if (!SI1)
+    return false;
+
+  if (const SelectInst *SI2 = dyn_cast<SelectInst>(V2)) {
+    if (SI1->getCondition() == SI2->getCondition())
+      return isKnownNonEqual(SI1->getTrueValue(), SI2->getTrueValue(),
+                             Depth + 1, Q) &&
+             isKnownNonEqual(SI1->getFalseValue(), SI2->getFalseValue(),
+                             Depth + 1, Q);
+  }
+  return isKnownNonEqual(SI1->getTrueValue(), V2, Depth + 1, Q) &&
+         isKnownNonEqual(SI1->getFalseValue(), V2, Depth + 1, Q);
+}
+
 /// Return true if it is known that V1 != V2.
 static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
                             const SimplifyQuery &Q) {
@@ -3142,6 +3159,9 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
     };
   }
 
+  if (isNonEqualSELECT(V1, V2, Depth, Q) || isNonEqualSELECT(V2, V1, Depth, Q))
+    return true;
+
   if (isAddOfNonZero(V1, V2, Depth, Q) || isAddOfNonZero(V2, V1, Depth, Q))
     return true;
 
diff --git a/llvm/test/Analysis/BasicAA/non-equal-select.ll b/llvm/test/Analysis/BasicAA/non-equal-select.ll
new file mode 100644
index 000000000000000..1af37245c6d85a6
--- /dev/null
+++ b/llvm/test/Analysis/BasicAA/non-equal-select.ll
@@ -0,0 +1,33 @@
+; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+ at G = global [10 x i32] zeroinitializer, align 4
+
+; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: none, inaccessiblemem: none) uwtable
+define void @select_in_gep1(i1 %c, i64 noundef %x) {
+entry:
+; CHECK: Function: select_in_gep1
+; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
+  %add1_ = add nsw i64 %x, 1
+  %add2_ = add nsw i64 %x, 2
+  %select_ = select i1 %c, i64 %add1_, i64 %add2_
+  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select_
+  store i32 42, ptr %arrayidx1, align 4
+  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %x
+  store i32 43, ptr %arrayidx2, align 4
+  ret void
+}
+
+define void @select_in_gep2(i1 %c, i64 noundef %x) {
+entry:
+  ; TODO: should be "NoAlias" here as well.
+; CHECK: Function: select_in_gep2
+; CHECK: MayAlias:     i32* %arrayidx1, i32* %arrayidx2
+  %add1_ = add nsw i64 %x, 1
+  %add2_ = add nsw i64 %x, 2
+  %add3_ = add nsw i64 %x, 3
+  %select_ = select i1 %c, i64 %add1_, i64 %add2_
+  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select_
+  store i32 42, ptr %arrayidx1, align 4
+  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %add3_
+  store i32 43, ptr %arrayidx2, align 4
+  ret void
+}

>From 110b9f3a5d79c8a66d059db350b0b0b0f970431d Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Sat, 7 Oct 2023 15:26:09 -0400
Subject: [PATCH 2/5] Addressed review comments

---
 llvm/lib/Analysis/ValueTracking.cpp           | 30 +++++--
 .../test/Analysis/BasicAA/non-equal-select.ll | 88 +++++++++++++++++--
 2 files changed, 106 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 1c284e8d85ca417..b42b9f85efd2136 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3112,18 +3112,34 @@ static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2,
   return true;
 }
 
-static bool isNonEqualSELECT(const Value *V1, const Value *V2, unsigned Depth,
+static bool isNonEqualSelect(const Value *V1, const Value *V2, unsigned Depth,
                              const SimplifyQuery &Q) {
   const SelectInst *SI1 = dyn_cast<SelectInst>(V1);
   if (!SI1)
     return false;
 
   if (const SelectInst *SI2 = dyn_cast<SelectInst>(V2)) {
-    if (SI1->getCondition() == SI2->getCondition())
-      return isKnownNonEqual(SI1->getTrueValue(), SI2->getTrueValue(),
-                             Depth + 1, Q) &&
-             isKnownNonEqual(SI1->getFalseValue(), SI2->getFalseValue(),
-                             Depth + 1, Q);
+    const Value *TVal1 = nullptr;
+    const Value *TVal2 = nullptr;
+    const Value *FVal1 = nullptr;
+    const Value *FVal2 = nullptr;
+    const Value *Cond1 = SI1->getCondition();
+    const Value *Cond2 = SI2->getCondition();
+    if (Cond1 == Cond2) {
+      TVal1 = SI1->getTrueValue();
+      TVal2 = SI2->getTrueValue();
+      FVal1 = SI1->getFalseValue();
+      FVal2 = SI2->getFalseValue();
+    }
+    if (match(Cond1, m_Not(m_Specific(Cond2)))) {
+      TVal1 = SI1->getFalseValue();
+      TVal2 = SI2->getTrueValue();
+      FVal1 = SI1->getTrueValue();
+      FVal2 = SI2->getFalseValue();
+    }
+    if (TVal1)
+      return isKnownNonEqual(TVal1, TVal2, Depth + 1, Q) &&
+             isKnownNonEqual(FVal1, FVal2, Depth + 1, Q);
   }
   return isKnownNonEqual(SI1->getTrueValue(), V2, Depth + 1, Q) &&
          isKnownNonEqual(SI1->getFalseValue(), V2, Depth + 1, Q);
@@ -3159,7 +3175,7 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
     };
   }
 
-  if (isNonEqualSELECT(V1, V2, Depth, Q) || isNonEqualSELECT(V2, V1, Depth, Q))
+  if (isNonEqualSelect(V1, V2, Depth, Q) || isNonEqualSelect(V2, V1, Depth, Q))
     return true;
 
   if (isAddOfNonZero(V1, V2, Depth, Q) || isAddOfNonZero(V2, V1, Depth, Q))
diff --git a/llvm/test/Analysis/BasicAA/non-equal-select.ll b/llvm/test/Analysis/BasicAA/non-equal-select.ll
index 1af37245c6d85a6..c4e99729f7f2597 100644
--- a/llvm/test/Analysis/BasicAA/non-equal-select.ll
+++ b/llvm/test/Analysis/BasicAA/non-equal-select.ll
@@ -1,10 +1,9 @@
 ; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
 @G = global [10 x i32] zeroinitializer, align 4
 
-; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: none, inaccessiblemem: none) uwtable
-define void @select_in_gep1(i1 %c, i64 noundef %x) {
+define void @select_in_gep1(i1 %c, i64 %x) {
 entry:
-; CHECK: Function: select_in_gep1
+; CHECK-LABEL: Function: select_in_gep1
 ; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
   %add1_ = add nsw i64 %x, 1
   %add2_ = add nsw i64 %x, 2
@@ -16,10 +15,10 @@ entry:
   ret void
 }
 
-define void @select_in_gep2(i1 %c, i64 noundef %x) {
+define void @select_in_gep2(i1 %c, i64 %x) {
 entry:
   ; TODO: should be "NoAlias" here as well.
-; CHECK: Function: select_in_gep2
+; CHECK-LABEL: Function: select_in_gep2
 ; CHECK: MayAlias:     i32* %arrayidx1, i32* %arrayidx2
   %add1_ = add nsw i64 %x, 1
   %add2_ = add nsw i64 %x, 2
@@ -31,3 +30,82 @@ entry:
   store i32 43, ptr %arrayidx2, align 4
   ret void
 }
+
+define void @two_selects_in_gep_same_cond(i1 %c, i64 %x) {
+entry:
+; CHECK-LABEL: Function: two_selects_in_gep_same_cond
+; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
+  %add1_ = add nsw i64 %x, 1
+  %add2_ = add nsw i64 %x, 2
+  %select1_ = select i1 %c, i64 %x, i64 %add1_
+  %select2_ = select i1 %c, i64 %add2_, i64 %x
+  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_
+  store i32 42, ptr %arrayidx1, align 4
+  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_
+  store i32 43, ptr %arrayidx2, align 4
+  ret void
+}
+
+define void @two_selects_in_gep_opposite_cond1(i1 %c, i64 %x) {
+entry:
+; CHECK-LABEL: Function: two_selects_in_gep_opposite_cond1
+; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
+  %add1_ = add nsw i64 %x, 1
+  %add2_ = add nsw i64 %x, 2
+  %not_c = xor i1 %c, -1
+  %select1_ = select i1 %c, i64 %x, i64 %add1_
+  %select2_ = select i1 %not_c, i64 %x, i64 %add2_
+  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_
+  store i32 42, ptr %arrayidx1, align 4
+  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_
+  store i32 43, ptr %arrayidx2, align 4
+  ret void
+}
+
+define void @two_selects_in_gep_opposite_cond2(i1 %c, i64 %x) {
+entry:
+; CHECK-LABEL: Function: two_selects_in_gep_opposite_cond2
+; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
+  %add1_ = add nsw i64 %x, 1
+  %add2_ = add nsw i64 %x, 2
+  %not_c = xor i1 %c, -1
+  %select1_ = select i1 %not_c, i64 %x, i64 %add1_
+  %select2_ = select i1 %c, i64 %x, i64 %add2_
+  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_
+  store i32 42, ptr %arrayidx1, align 4
+  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_
+  store i32 43, ptr %arrayidx2, align 4
+  ret void
+}
+
+define void @two_selects_in_gep_different_cond1(i1 %c1, i1 %c2, i64 %x) {
+entry:
+; CHECK-LABEL: Function: two_selects_in_gep_different_cond1
+; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
+  %add1_ = add nsw i64 %x, 1
+  %add2_ = add nsw i64 %x, 2
+  %add3_ = add nsw i64 %x, 3
+  %add4_ = add nsw i64 %x, 4
+  %select1_ = select i1 %c1, i64 %add1_, i64 %add2_
+  %select2_ = select i1 %c2, i64 %add3_, i64 %add4_
+  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_
+  store i32 42, ptr %arrayidx1, align 4
+  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_
+  store i32 43, ptr %arrayidx2, align 4
+  ret void
+}
+
+define void @two_selects_in_gep_different_cond2(i1 %c1, i1 %c2, i64 %x) {
+entry:
+; CHECK-LABEL: Function: two_selects_in_gep_different_cond2
+; CHECK: MayAlias: i32* %arrayidx1, i32* %arrayidx2
+  %add1_ = add nsw i64 %x, 1
+  %add2_ = add nsw i64 %x, 2
+  %select1_ = select i1 %c1, i64 %x, i64 %add1_
+  %select2_ = select i1 %c2, i64 %x, i64 %add2_
+  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_
+  store i32 42, ptr %arrayidx1, align 4
+  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_
+  store i32 43, ptr %arrayidx2, align 4
+  ret void
+}

>From cd8f051d252ddf3988b28313570b0916b8e8a5dd Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Mon, 9 Oct 2023 12:32:07 -0400
Subject: [PATCH 3/5] Deleted the case of two `select`s with opposite
 conditions.

---
 llvm/lib/Analysis/ValueTracking.cpp           | 24 +++-----------
 .../test/Analysis/BasicAA/non-equal-select.ll | 32 -------------------
 2 files changed, 5 insertions(+), 51 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b42b9f85efd2136..48e88d7cc3993d9 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3119,27 +3119,13 @@ static bool isNonEqualSelect(const Value *V1, const Value *V2, unsigned Depth,
     return false;
 
   if (const SelectInst *SI2 = dyn_cast<SelectInst>(V2)) {
-    const Value *TVal1 = nullptr;
-    const Value *TVal2 = nullptr;
-    const Value *FVal1 = nullptr;
-    const Value *FVal2 = nullptr;
     const Value *Cond1 = SI1->getCondition();
     const Value *Cond2 = SI2->getCondition();
-    if (Cond1 == Cond2) {
-      TVal1 = SI1->getTrueValue();
-      TVal2 = SI2->getTrueValue();
-      FVal1 = SI1->getFalseValue();
-      FVal2 = SI2->getFalseValue();
-    }
-    if (match(Cond1, m_Not(m_Specific(Cond2)))) {
-      TVal1 = SI1->getFalseValue();
-      TVal2 = SI2->getTrueValue();
-      FVal1 = SI1->getTrueValue();
-      FVal2 = SI2->getFalseValue();
-    }
-    if (TVal1)
-      return isKnownNonEqual(TVal1, TVal2, Depth + 1, Q) &&
-             isKnownNonEqual(FVal1, FVal2, Depth + 1, Q);
+    if (Cond1 == Cond2)
+      return isKnownNonEqual(SI1->getTrueValue(), SI2->getTrueValue(),
+                             Depth + 1, Q) &&
+             isKnownNonEqual(SI1->getFalseValue(), SI2->getFalseValue(),
+                             Depth + 1, Q);
   }
   return isKnownNonEqual(SI1->getTrueValue(), V2, Depth + 1, Q) &&
          isKnownNonEqual(SI1->getFalseValue(), V2, Depth + 1, Q);
diff --git a/llvm/test/Analysis/BasicAA/non-equal-select.ll b/llvm/test/Analysis/BasicAA/non-equal-select.ll
index c4e99729f7f2597..fe38a57eeb1b477 100644
--- a/llvm/test/Analysis/BasicAA/non-equal-select.ll
+++ b/llvm/test/Analysis/BasicAA/non-equal-select.ll
@@ -46,38 +46,6 @@ entry:
   ret void
 }
 
-define void @two_selects_in_gep_opposite_cond1(i1 %c, i64 %x) {
-entry:
-; CHECK-LABEL: Function: two_selects_in_gep_opposite_cond1
-; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
-  %add1_ = add nsw i64 %x, 1
-  %add2_ = add nsw i64 %x, 2
-  %not_c = xor i1 %c, -1
-  %select1_ = select i1 %c, i64 %x, i64 %add1_
-  %select2_ = select i1 %not_c, i64 %x, i64 %add2_
-  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_
-  store i32 42, ptr %arrayidx1, align 4
-  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_
-  store i32 43, ptr %arrayidx2, align 4
-  ret void
-}
-
-define void @two_selects_in_gep_opposite_cond2(i1 %c, i64 %x) {
-entry:
-; CHECK-LABEL: Function: two_selects_in_gep_opposite_cond2
-; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2
-  %add1_ = add nsw i64 %x, 1
-  %add2_ = add nsw i64 %x, 2
-  %not_c = xor i1 %c, -1
-  %select1_ = select i1 %not_c, i64 %x, i64 %add1_
-  %select2_ = select i1 %c, i64 %x, i64 %add2_
-  %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_
-  store i32 42, ptr %arrayidx1, align 4
-  %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_
-  store i32 43, ptr %arrayidx2, align 4
-  ret void
-}
-
 define void @two_selects_in_gep_different_cond1(i1 %c1, i1 %c2, i64 %x) {
 entry:
 ; CHECK-LABEL: Function: two_selects_in_gep_different_cond1

>From e44a2cd604350bc1e22e5dab58d1200c09342a60 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 10 Oct 2023 01:10:53 -0400
Subject: [PATCH 4/5] Moved `isNonEqualSelect` to the end of `isKnownNonEqual`.

This is necessary so that we can analyze things like
`isKnownNonEqual(X, Y)` where `X = select ... ` and `Y = shl X, 2` for
example. In other words, we first should try to do the analysis without
"decomposing" `select` first.
---
 llvm/lib/Analysis/ValueTracking.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 48e88d7cc3993d9..eb6fcaf83df0e31 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3161,9 +3161,6 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
     };
   }
 
-  if (isNonEqualSelect(V1, V2, Depth, Q) || isNonEqualSelect(V2, V1, Depth, Q))
-    return true;
-
   if (isAddOfNonZero(V1, V2, Depth, Q) || isAddOfNonZero(V2, V1, Depth, Q))
     return true;
 
@@ -3183,6 +3180,10 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
         Known2.Zero.intersects(Known1.One))
       return true;
   }
+
+  if (isNonEqualSelect(V1, V2, Depth, Q) || isNonEqualSelect(V2, V1, Depth, Q))
+    return true;
+
   return false;
 }
 

>From 41a1dda8f061dc81fd958ab89e7b2ac622313079 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 10 Oct 2023 13:21:30 -0400
Subject: [PATCH 5/5] Update llvm/lib/Analysis/ValueTracking.cpp

Co-authored-by: Nikita Popov <github at npopov.com>
---
 llvm/lib/Analysis/ValueTracking.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index eb6fcaf83df0e31..b4664e9b2ff7d17 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3119,9 +3119,7 @@ static bool isNonEqualSelect(const Value *V1, const Value *V2, unsigned Depth,
     return false;
 
   if (const SelectInst *SI2 = dyn_cast<SelectInst>(V2)) {
-    const Value *Cond1 = SI1->getCondition();
-    const Value *Cond2 = SI2->getCondition();
-    if (Cond1 == Cond2)
+    if (SI1->getCondition() == SI2->getCondition())
       return isKnownNonEqual(SI1->getTrueValue(), SI2->getTrueValue(),
                              Depth + 1, Q) &&
              isKnownNonEqual(SI1->getFalseValue(), SI2->getFalseValue(),



More information about the llvm-commits mailing list