diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 2c2f965a3cd6f..23bf06222d534 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -736,6 +736,10 @@ inline Value *getUnderlyingObject(Value *V, unsigned MaxLookup = 6) { return const_cast(getUnderlyingObject(VConst, MaxLookup)); } +/// Like getUnderlyingObject(), but will try harder to find a single underlying +/// object. In particular, this function also looks through selects and phis. +const Value *getUnderlyingObjectAggressive(const Value *V); + /// This method is similar to getUnderlyingObject except that it can /// look through phi and select instructions and return multiple objects. /// diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp index 1d54a66705a2a..0dd4a3de08e5c 100644 --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -743,9 +743,8 @@ static bool isPointerAlwaysReplaceable(const Value *From, const Value *To, if (isa(To) && isDereferenceablePointer(To, Type::getInt8Ty(To->getContext()), DL)) return true; - if (getUnderlyingObject(From) == getUnderlyingObject(To)) - return true; - return false; + return getUnderlyingObjectAggressive(From) == + getUnderlyingObjectAggressive(To); } bool llvm::canReplacePointersInUseIfEqual(const Use &U, const Value *To, diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 535a248a5f1a2..20056c7e8d894 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -6609,6 +6609,48 @@ void llvm::getUnderlyingObjects(const Value *V, } while (!Worklist.empty()); } +const Value *llvm::getUnderlyingObjectAggressive(const Value *V) { + const unsigned MaxVisited = 8; + + SmallPtrSet Visited; + SmallVector Worklist; + Worklist.push_back(V); + const Value *Object = nullptr; + // Used as fallback if we can't find a common underlying object through + // recursion. + bool First = true; + const Value *FirstObject = getUnderlyingObject(V); + do { + const Value *P = Worklist.pop_back_val(); + P = First ? FirstObject : getUnderlyingObject(P); + First = false; + + if (!Visited.insert(P).second) + continue; + + if (Visited.size() == MaxVisited) + return FirstObject; + + if (auto *SI = dyn_cast(P)) { + Worklist.push_back(SI->getTrueValue()); + Worklist.push_back(SI->getFalseValue()); + continue; + } + + if (auto *PN = dyn_cast(P)) { + append_range(Worklist, PN->incoming_values()); + continue; + } + + if (!Object) + Object = P; + else if (Object != P) + return FirstObject; + } while (!Worklist.empty()); + + return Object; +} + /// This is the function that does the work of looking through basic /// ptrtoint+arithmetic+inttoptr sequences. static const Value *getUnderlyingObjectFromInt(const Value *V) { diff --git a/llvm/test/Transforms/GVN/condprop.ll b/llvm/test/Transforms/GVN/condprop.ll index 02f4bb97d7ebd..3babdd8173a21 100644 --- a/llvm/test/Transforms/GVN/condprop.ll +++ b/llvm/test/Transforms/GVN/condprop.ll @@ -813,7 +813,7 @@ define void @select_same_obj(i1 %c, ptr %p, i64 %x) { ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[EXIT:%.*]] ; CHECK: if: ; CHECK-NEXT: call void @use_ptr(ptr [[P]]) -; CHECK-NEXT: call void @use_ptr(ptr [[P3]]) +; CHECK-NEXT: call void @use_ptr(ptr [[P]]) ; CHECK-NEXT: ret void ; CHECK: exit: ; CHECK-NEXT: ret void @@ -902,7 +902,7 @@ define void @phi_same_obj(i1 %c, ptr %p, i64 %x) { ; CHECK-NEXT: br i1 [[CMP]], label [[IF2:%.*]], label [[EXIT:%.*]] ; CHECK: if2: ; CHECK-NEXT: call void @use_ptr(ptr [[P]]) -; CHECK-NEXT: call void @use_ptr(ptr [[P3]]) +; CHECK-NEXT: call void @use_ptr(ptr [[P]]) ; CHECK-NEXT: ret void ; CHECK: exit: ; CHECK-NEXT: ret void @@ -975,7 +975,7 @@ define void @phi_same_obj_cycle(i1 %c, ptr %p, i64 %x) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P_IV]], [[P]] ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[LOOP_LATCH]] ; CHECK: if: -; CHECK-NEXT: call void @use_ptr(ptr [[P_IV]]) +; CHECK-NEXT: call void @use_ptr(ptr [[P]]) ; CHECK-NEXT: call void @use_ptr(ptr [[P]]) ; CHECK-NEXT: br label [[LOOP_LATCH]] ; CHECK: loop.latch: