diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -168,6 +168,10 @@ const DominatorTree *DT = nullptr, bool UseInstrInfo = true); +/// Check if an assume intrinsic covers the non-equality information +bool getKnownNonEqualFromAssume(const Value *V1, const Value *V2, + const SimplifyQuery &Q); + /// Return true if the given values are known to be non-equal when defined. /// Supports scalar integer types only. bool isKnownNonEqual(const Value *V1, const Value *V2, const DataLayout &DL, 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 @@ -3117,6 +3117,51 @@ return true; } +bool llvm::getKnownNonEqualFromAssume(const Value *V1, const Value *V2, + const SimplifyQuery &Q) { + // Use of assumptions is context-sensitive. If we don't have a context, we + // cannot use them! + if (!Q.AC || !Q.CxtI) + return false; + + // Note that the patterns below need to be kept in sync with the code + // in AssumptionCache::updateAffectedValues. + + for (auto &AssumeVH : Q.AC->assumptionsFor(V1)) { + if (!AssumeVH) + continue; + + CallInst *I = cast(AssumeVH); + assert(I->getParent()->getParent() == Q.CxtI->getParent()->getParent() && + "Got assumption for the wrong function!"); + + // Warning: This loop can end up being somewhat performance sensitive. + // We're running this loop for once for each value queried resulting in a + // runtime of ~O(#assumes * #values). + + assert(I->getCalledFunction()->getIntrinsicID() == Intrinsic::assume && + "must be an assume intrinsic"); + + Value *Arg = I->getArgOperand(0); + ICmpInst *Cmp = dyn_cast(Arg); + if (!Cmp || !Cmp->isEquality()) + continue; + + // If we have a matching assumption: + // - EQ: return false + // - NE: return true + Value *Op0 = Cmp->getOperand(0); + Value *Op1 = Cmp->getOperand(1); + if (!(Op0 == V1 && Op1 == V2) && !(Op0 == V2 && Op1 == V1)) + continue; + + if (isValidAssumeForContext(I, Q.CxtI, Q.DT)) + return Cmp->getPredicate() == CmpInst::ICMP_NE; + } + + return false; +} + /// Return true if it is known that V1 != V2. static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth, const SimplifyQuery &Q) { @@ -3166,7 +3211,9 @@ Known2.Zero.intersects(Known1.One)) return true; } - return false; + + // Check whether a nearby assume intrinsic can determine non-equality. + return getKnownNonEqualFromAssume(V1, V2, Q); } /// Return true if 'V & Mask' is known to be zero. We use this predicate to 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 @@ -1,6 +1,9 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=instsimplify < %s -S | FileCheck %s +declare void @llvm.assume(i1) +declare void @use.i1(i1) + define i1 @test(ptr %pq, i8 %B) { ; CHECK-LABEL: @test( ; CHECK-NEXT: ret i1 false @@ -1813,5 +1816,44 @@ ret i1 %res } +; Take the information about non-equality from a nearby assumption intrinsic call - ne +; This test tries to take advantage of the following simplification: icmp eq|ne X, Y -> false|true if X != Y +define i1 @from_assumption_ne(i16 %x) { +; CHECK-LABEL: @from_assumption_ne( +; CHECK-NEXT: [[NE:%.*]] = icmp ne i16 [[X:%.*]], 56 +; CHECK-NEXT: call void @llvm.assume(i1 [[NE]]) +; CHECK-NEXT: call void @use.i1(i1 false) +; CHECK-NEXT: call void @use.i1(i1 true) +; CHECK-NEXT: ret i1 true +; + %ne = icmp ne i16 %x, 56 + call void @llvm.assume(i1 %ne) + %res1 = icmp eq i16 %x, 56 + call void @use.i1(i1 %res1) + %res2 = icmp ne i16 56, %x + call void @use.i1(i1 %res2) + %res = or i1 %res1, %res2 + ret i1 %res +} + +; Take the information about non-equality from a nearby assumption intrinsic call - eq +; This test tries to take advantage of the following simplification: icmp eq|ne X, Y -> false|true if X != Y +define i1 @from_assumption_eq(i64 %x, i64 %y) { +; CHECK-LABEL: @from_assumption_eq( +; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: call void @llvm.assume(i1 [[EQ]]) +; CHECK-NEXT: call void @use.i1(i1 true) +; CHECK-NEXT: call void @use.i1(i1 false) +; CHECK-NEXT: ret i1 true +; + %eq = icmp eq i64 %y, %x + call void @llvm.assume(i1 %eq) + %res1 = icmp eq i64 %x, %y + call void @use.i1(i1 %res1) + %res2 = icmp ne i64 %y, %x + call void @use.i1(i1 %res2) + %res = or i1 %res1, %res2 + ret i1 %res +} !0 = !{ i8 1, i8 5 }