diff options
author | Yingwei Zheng <dtcxzyw2333@gmail.com> | 2025-02-12 20:15:14 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-12 20:15:14 +0800 |
commit | 324e27e8bad83ca23a3cd276d7e2e729b1b0b8c7 (patch) | |
tree | f5389a98a22aea896ef40f5dbdc4416db474cf64 /llvm | |
parent | 085bdb1e4c0b584aba84d90bf72997f6476881bc (diff) | |
download | llvm-324e27e8bad83ca23a3cd276d7e2e729b1b0b8c7.zip llvm-324e27e8bad83ca23a3cd276d7e2e729b1b0b8c7.tar.gz llvm-324e27e8bad83ca23a3cd276d7e2e729b1b0b8c7.tar.bz2 |
[ValueTracking] Infer NonEqual from dominating conditions/assumptions (#117442)
This patch adds context-sensitive analysis support for
`isKnownNonEqual`. It is required for
https://github.com/llvm/llvm-project/issues/117436.
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 49 | ||||
-rw-r--r-- | llvm/test/Analysis/BasicAA/fallback-mayalias.ll | 2 | ||||
-rw-r--r-- | llvm/test/Transforms/InstCombine/icmp-dom.ll | 200 |
3 files changed, 248 insertions, 3 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 28d7e1c..2a49a10 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3857,6 +3857,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; } @@ -10231,10 +10275,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). @@ -10248,6 +10292,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/Analysis/BasicAA/fallback-mayalias.ll b/llvm/test/Analysis/BasicAA/fallback-mayalias.ll index 8613518..52eb494 100644 --- a/llvm/test/Analysis/BasicAA/fallback-mayalias.ll +++ b/llvm/test/Analysis/BasicAA/fallback-mayalias.ll @@ -3,7 +3,7 @@ ; Check that BasicAA falls back to MayAlias (instead of PartialAlias) when none ; of its little tricks are applicable. -; CHECK: MayAlias: float* %arrayidxA, float* %arrayidxB +; CHECK: NoAlias: float* %arrayidxA, float* %arrayidxB define void @fallback_mayalias(ptr noalias nocapture %C, i64 %i, i64 %j) local_unnamed_addr { entry: diff --git a/llvm/test/Transforms/InstCombine/icmp-dom.ll b/llvm/test/Transforms/InstCombine/icmp-dom.ll index 3cf3a7a..07793e8 100644 --- a/llvm/test/Transforms/InstCombine/icmp-dom.ll +++ b/llvm/test/Transforms/InstCombine/icmp-dom.ll @@ -534,3 +534,203 @@ else: %cmp1 = icmp eq i32 %and1, 0 ret i1 %cmp1 } + +; TODO: X != Y implies X | Y != 0 +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: [[OR:%.*]] = or i8 [[X]], [[Y]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +; 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() |