-
Notifications
You must be signed in to change notification settings - Fork 14k
[ValueTracking] Infer X | Y != 0
from X != Y
#117443
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
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-analysis Author: Yingwei Zheng (dtcxzyw) ChangesAlive2: https://alive2.llvm.org/ce/z/cJ75Ya Full diff: https://github.com/llvm/llvm-project/pull/117443.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c48068afc04816..d882b393bddfec 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2910,6 +2910,10 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
// (X | (X != 0)) is non zero
if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
return true;
+ // X | Y != 0 if X != Y.
+ if (isKnownNonEqual(I->getOperand(0), I->getOperand(1), DemandedElts, Depth,
+ Q))
+ return true;
// X | Y != 0 if X != 0 or Y != 0.
return isKnownNonZero(I->getOperand(1), DemandedElts, Q, Depth) ||
isKnownNonZero(I->getOperand(0), DemandedElts, Q, Depth);
@@ -3748,6 +3752,50 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2,
match(V2, m_PtrToIntSameSize(Q.DL, m_Value(B))))
return isKnownNonEqual(A, B, DemandedElts, Depth + 1, Q);
+ if (!Q.CxtI)
+ return false;
+
+ // Try to infer NonEqual based on information from dominating conditions.
+ if (Q.DC && Q.DT) {
+ for (BranchInst *BI : Q.DC->conditionsFor(V1)) {
+ Value *Cond = BI->getCondition();
+ BasicBlockEdge Edge0(BI->getParent(), BI->getSuccessor(0));
+ if (Q.DT->dominates(Edge0, Q.CxtI->getParent()) &&
+ isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ /*LHSIsTrue=*/true, Depth)
+ .value_or(false))
+ return true;
+
+ BasicBlockEdge Edge1(BI->getParent(), BI->getSuccessor(1));
+ if (Q.DT->dominates(Edge1, Q.CxtI->getParent()) &&
+ isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ /*LHSIsTrue=*/false, Depth)
+ .value_or(false))
+ return true;
+ }
+ }
+
+ if (!Q.AC)
+ return false;
+
+ // Try to infer NonEqual based on information from assumptions.
+ for (auto &AssumeVH : Q.AC->assumptionsFor(V1)) {
+ if (!AssumeVH)
+ continue;
+ CallInst *I = cast<CallInst>(AssumeVH);
+
+ assert(I->getFunction() == Q.CxtI->getFunction() &&
+ "Got assumption for the wrong function!");
+ assert(I->getIntrinsicID() == Intrinsic::assume &&
+ "must be an assume intrinsic");
+
+ if (isImpliedCondition(I->getArgOperand(0), ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ /*LHSIsTrue=*/true, Depth)
+ .value_or(false) &&
+ isValidAssumeForContext(I, Q.CxtI, Q.DT))
+ return true;
+ }
+
return false;
}
@@ -10037,10 +10085,10 @@ void llvm::findValuesAffectedByCondition(
Worklist.push_back(B);
}
} else if (match(V, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
- AddCmpOperands(A, B);
-
bool HasRHSC = match(B, m_ConstantInt());
if (ICmpInst::isEquality(Pred)) {
+ AddAffected(A);
+ AddAffected(B);
if (HasRHSC) {
Value *Y;
// (X & C) or (X | C) or (X ^ C).
@@ -10055,6 +10103,7 @@ void llvm::findValuesAffectedByCondition(
}
}
} else {
+ AddCmpOperands(A, B);
if (HasRHSC) {
// Handle (A + C1) u< C2, which is the canonical form of
// A > C3 && A < C4.
diff --git a/llvm/test/Transforms/InstCombine/icmp-dom.ll b/llvm/test/Transforms/InstCombine/icmp-dom.ll
index 3cf3a7af77041c..d3c292551b4879 100644
--- a/llvm/test/Transforms/InstCombine/icmp-dom.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-dom.ll
@@ -534,3 +534,200 @@ else:
%cmp1 = icmp eq i32 %and1, 0
ret i1 %cmp1
}
+
+define i1 @or_nonzero_from_nonequal(i8 %x, i8 %y) {
+; CHECK-LABEL: @or_nonzero_from_nonequal(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i1 false
+; CHECK: if.else:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond = icmp eq i8 %x, %y
+ br i1 %cond, label %if.else, label %if.then
+
+if.then:
+ %or = or i8 %x, %y
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+
+if.else:
+ ret i1 false
+}
+
+define i1 @test_nonequal_domcond1(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_domcond1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i1 false
+; CHECK: if.end:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond1 = icmp eq i64 %y, %x
+ %cond2 = icmp eq i64 %w, %z
+ %or.cond = select i1 %cond1, i1 true, i1 %cond2
+ br i1 %or.cond, label %if.end, label %if.then
+
+if.then:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+
+if.end:
+ ret i1 false
+}
+
+define i1 @test_nonequal_domcond2(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_domcond2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 [[COND2]], i1 false
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i1 false
+; CHECK: if.end:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond1 = icmp ne i64 %y, %x
+ %cond2 = icmp ne i64 %w, %z
+ %or.cond = select i1 %cond1, i1 %cond2, i1 false
+ br i1 %or.cond, label %if.then, label %if.end
+
+if.then:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+
+if.end:
+ ret i1 false
+}
+
+define i1 @test_nonequal_assume(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_assume(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
+; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]])
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond1 = icmp ne i64 %y, %x
+ call void @llvm.assume(i1 %cond1)
+ %cond2 = icmp ne i64 %w, %z
+ call void @llvm.assume(i1 %cond2)
+
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+}
+
+; Negative tests
+
+define i1 @test_nonequal_invalid_domcond1(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_invalid_domcond1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i1 true
+; CHECK: if.end:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond1 = icmp ne i64 %y, %x
+ %cond2 = icmp eq i64 %w, %z
+ %or.cond = select i1 %cond1, i1 true, i1 %cond2
+ br i1 %or.cond, label %if.end, label %if.then
+
+if.then:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+
+if.end:
+ ret i1 false
+}
+
+define i1 @test_nonequal_invalid_domcond2(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_invalid_domcond2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
+; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
+; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+entry:
+ %cond1 = icmp eq i64 %y, %x
+ %cond2 = icmp eq i64 %w, %z
+ %or.cond = select i1 %cond1, i1 true, i1 %cond2
+ br i1 %or.cond, label %if.then, label %if.end
+
+if.then:
+ br label %if.end
+
+if.end:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+}
+
+define i1 @test_nonequal_invalid_assume(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_invalid_assume(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
+; CHECK-NEXT: call void @side_effect()
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y]], [[X]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
+; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W]], [[Z]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]])
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+entry:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+
+ call void @side_effect()
+ %cond1 = icmp ne i64 %y, %x
+ call void @llvm.assume(i1 %cond1)
+ %cond2 = icmp ne i64 %w, %z
+ call void @llvm.assume(i1 %cond2)
+ ret i1 %cmp
+}
+
+declare void @side_effect()
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebase now that the first PR has landed?
6041815
to
2eb61d2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but probably needs a rebase to account for Depth changes.
2eb61d2
to
da17850
Compare
Alive2: https://alive2.llvm.org/ce/z/cJ75Ya
Stacked on #117442
Closes #117436.