Skip to content

[ValueTracking] Analyze Select in isKnownNonEqual. #68427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 25, 2023

Conversation

mgudim
Copy link
Contributor

@mgudim mgudim commented Oct 6, 2023

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.

@mgudim mgudim requested a review from nikic as a code owner October 6, 2023 16:33
@mgudim mgudim requested a review from goldsteinn October 6, 2023 16:33
@llvmbot
Copy link
Member

llvmbot commented Oct 6, 2023

@llvm/pr-subscribers-llvm-analysis

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/68427.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+20)
  • (added) llvm/test/Analysis/BasicAA/non-equal-select.ll (+33)
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
+@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
+}

@mgudim mgudim force-pushed the is-non-equal-select branch 3 times, most recently from 416a152 to 579e829 Compare October 8, 2023 16:55
@mgudim mgudim force-pushed the is-non-equal-select branch from 579e829 to 604c83a Compare October 9, 2023 16:33
@github-actions
Copy link

github-actions bot commented Oct 9, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@mgudim mgudim force-pushed the is-non-equal-select branch from 604c83a to cd8f051 Compare October 9, 2023 17:32
@mgudim
Copy link
Contributor Author

mgudim commented Oct 10, 2023

@nikic @goldsteinn I added a new commit moving the 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. If that doesn't succeed then we try isNonEqualSelect.

@nikic
Copy link
Contributor

nikic commented Oct 10, 2023

@nikic @goldsteinn I added a new commit moving the 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. If that doesn't succeed then we try isNonEqualSelect.

I don't understand what you mean here. If isNonEqualSelect() returns false, then all the following code still gets executed, no? It shouldn't matter (for behavior) in which order these calls are executed.

@mgudim
Copy link
Contributor Author

mgudim commented Oct 10, 2023

I don't understand what you mean here. If isNonEqualSelect() returns false, then all the following code still gets executed, no? It shouldn't matter (for behavior) in which order these calls are executed.

Right, I just thought it's better to do cheaper checks first.

@mgudim
Copy link
Contributor Author

mgudim commented Oct 23, 2023

@nikic @goldsteinn ping

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

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`.
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.
@mgudim mgudim force-pushed the is-non-equal-select branch from 41a1dda to 8e64ec8 Compare October 25, 2023 03:41
@mgudim mgudim merged commit 9abf3df into llvm:main Oct 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants