diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2548,6 +2548,36 @@ return false; } +static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2, + unsigned Depth, const Query &Q) { + // Check two PHIs are in same block. + if (PN1->getParent() != PN2->getParent()) + return false; + + SmallPtrSet VisitedBBs; + bool UsedFullRecursion = false; + for (const BasicBlock *IncomBB : PN1->blocks()) { + if (!VisitedBBs.insert(IncomBB).second) + continue; // Don't reprocess blocks that we have dealt with already. + const Value *IV1 = PN1->getIncomingValueForBlock(IncomBB); + const Value *IV2 = PN2->getIncomingValueForBlock(IncomBB); + const APInt *C1, *C2; + if (match(IV1, m_APInt(C1)) && match(IV2, m_APInt(C2)) && *C1 != *C2) + continue; + + // Only one pair of phi operands is allowed for full recursion. + if (UsedFullRecursion) + return false; + + Query RecQ = Q; + RecQ.CxtI = IncomBB->getTerminator(); + if (!isKnownNonEqual(IV1, IV2, Depth + 1, RecQ)) + return false; + UsedFullRecursion = true; + } + return true; +} + /// Return true if it is known that V1 != V2. static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth, const Query &Q) { @@ -2599,12 +2629,20 @@ case Instruction::SExt: case Instruction::ZExt: if (O1->getOperand(0)->getType() == O2->getOperand(0)->getType()) - return isKnownNonEqual(O1->getOperand(0), O2->getOperand(0), - Depth + 1, Q); + return isKnownNonEqual(O1->getOperand(0), O2->getOperand(0), Depth + 1, + Q); + break; + case Instruction::PHI: + const PHINode *PN1 = cast(V1); + const PHINode *PN2 = cast(V2); + // FIXME: This is missing a generalization to handle the case where one is + // a PHI and another one isn't. + if (isNonEqualPHIs(PN1, PN2, Depth, Q)) + return true; break; }; } - + if (isAddOfNonZero(V1, V2, Depth, Q) || isAddOfNonZero(V2, V1, Depth, Q)) return true; diff --git a/llvm/test/Analysis/ValueTracking/known-non-equal.ll b/llvm/test/Analysis/ValueTracking/known-non-equal.ll --- a/llvm/test/Analysis/ValueTracking/known-non-equal.ll +++ b/llvm/test/Analysis/ValueTracking/known-non-equal.ll @@ -291,4 +291,56 @@ ret i1 %cmp } +define i1 @known_non_equal_phis(i8 %p, i8* %pq, i8 %n, i8 %r) { +; CHECK-LABEL: @known_non_equal_phis( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[A:%.*]] = phi i8 [ 2, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[NEXT]] = mul nsw i8 [[A]], 2 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[A]], [[N:%.*]] +; CHECK-NEXT: br i1 [[CMP1]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + br label %loop +loop: + %A = phi i8 [ 2, %entry ], [ %next, %loop ] + %B = phi i8 [ 3, %entry ], [ %A, %loop ] + %next = mul nsw i8 %A, 2 + %cmp1 = icmp eq i8 %A, %n + br i1 %cmp1, label %exit, label %loop +exit: + %cmp = icmp ne i8 %A, %B + ret i1 %cmp +} + +define i1 @known_non_equal_phis_fail(i8 %p, i8* %pq, i8 %n, i8 %r) { +; CHECK-LABEL: @known_non_equal_phis_fail( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[A:%.*]] = phi i8 [ 2, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[B:%.*]] = phi i8 [ 2, [[ENTRY]] ], [ [[A]], [[LOOP]] ] +; CHECK-NEXT: [[NEXT]] = mul nsw i8 [[A]], 2 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[A]], [[N:%.*]] +; CHECK-NEXT: br i1 [[CMP1]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + br label %loop +loop: + %A = phi i8 [ 2, %entry ], [ %next, %loop ] + %B = phi i8 [ 2, %entry ], [ %A, %loop ] + %next = mul nsw i8 %A, 2 + %cmp1 = icmp eq i8 %A, %n + br i1 %cmp1, label %exit, label %loop +exit: + %cmp = icmp ne i8 %A, %B + ret i1 %cmp +} + !0 = !{ i8 1, i8 5 }