diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -1623,10 +1623,17 @@ /// /// This method will evaluate \p Pred on all (transitive) uses of the /// associated value and return true if \p Pred holds every time. + /// If uses are skipped in favor of equivalent ones, e.g., if we look through + /// memory, the \p EquivalentUseCB will be used to give the caller an idea + /// what original used was replaced by a new one (or new ones). The visit is + /// cut short if \p EquivalentUseCB returns false and the function will return + /// false as well. bool checkForAllUses(function_ref Pred, const AbstractAttribute &QueryingAA, const Value &V, bool CheckBBLivenessOnly = false, - DepClassTy LivenessDepClass = DepClassTy::OPTIONAL); + DepClassTy LivenessDepClass = DepClassTy::OPTIONAL, + function_ref + EquivalentUseCB = nullptr); /// Emit a remark generically. /// diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -1011,10 +1011,11 @@ return false; } -bool Attributor::checkForAllUses(function_ref Pred, - const AbstractAttribute &QueryingAA, - const Value &V, bool CheckBBLivenessOnly, - DepClassTy LivenessDepClass) { +bool Attributor::checkForAllUses( + function_ref Pred, + const AbstractAttribute &QueryingAA, const Value &V, + bool CheckBBLivenessOnly, DepClassTy LivenessDepClass, + function_ref EquivalentUseCB) { // Check the trivial case first as it catches void values. if (V.use_empty()) @@ -1065,8 +1066,15 @@ << PotentialCopies.size() << " potential copies instead!\n"); for (Value *PotentialCopy : PotentialCopies) - for (const Use &U : PotentialCopy->uses()) - Worklist.push_back(&U); + for (const Use &CopyUse : PotentialCopy->uses()) { + if (EquivalentUseCB && !EquivalentUseCB(*U, CopyUse)) { + LLVM_DEBUG(dbgs() << "[Attributor] Potential copy was " + "reqjected by the equivalence call back: " + << *CopyUse << "!\n"); + return false; + } + Worklist.push_back(&CopyUse); + } continue; } } diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -1424,8 +1424,15 @@ LLVM_DEBUG(dbgs() << "[AAPointerInfo] User not handled " << *Usr << "\n"); return false; }; + auto EquivalentUseCB = [&](const Use &OldU, const Use &NewU) { + if (OffsetInfoMap.count(NewU)) + return OffsetInfoMap[NewU] == OffsetInfoMap[OldU]; + OffsetInfoMap[NewU] = OffsetInfoMap[OldU]; + return true; + }; if (!A.checkForAllUses(UsePred, *this, AssociatedValue, - /* CheckBBLivenessOnly */ true)) + /* CheckBBLivenessOnly */ true, DepClassTy::OPTIONAL, + EquivalentUseCB)) return indicatePessimisticFixpoint(); LLVM_DEBUG({ diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll --- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll @@ -4036,10 +4036,10 @@ @global = internal global %struct.STy zeroinitializer, align 8 -; FIXME: We should mark %dst as writeonly and %src as readonly, that is (for now) all we can expect. +; We mark %dst as writeonly and %src as readonly, that is (for now) all we can expect. define dso_local void @test_nested_memory(float* %dst, double* %src) { ; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test_nested_memory -; IS__TUNIT_OPM-SAME: (float* nocapture nofree [[DST:%.*]], double* nocapture nofree [[SRC:%.*]]) { +; IS__TUNIT_OPM-SAME: (float* nocapture nofree writeonly [[DST:%.*]], double* nocapture nofree readonly [[SRC:%.*]]) { ; IS__TUNIT_OPM-NEXT: entry: ; IS__TUNIT_OPM-NEXT: [[LOCAL:%.*]] = alloca [[STRUCT_STY:%.*]], align 8 ; IS__TUNIT_OPM-NEXT: [[INNER:%.*]] = getelementptr inbounds [[STRUCT_STY]], %struct.STy* [[LOCAL]], i64 0, i32 2 @@ -4055,7 +4055,7 @@ ; IS__TUNIT_OPM-NEXT: ret void ; ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test_nested_memory -; IS__TUNIT_NPM-SAME: (float* nocapture nofree [[DST:%.*]], double* nocapture nofree [[SRC:%.*]]) { +; IS__TUNIT_NPM-SAME: (float* nocapture nofree writeonly [[DST:%.*]], double* nocapture nofree readonly [[SRC:%.*]]) { ; IS__TUNIT_NPM-NEXT: entry: ; IS__TUNIT_NPM-NEXT: [[LOCAL:%.*]] = alloca [[STRUCT_STY:%.*]], align 8 ; IS__TUNIT_NPM-NEXT: [[INNER:%.*]] = getelementptr inbounds [[STRUCT_STY]], %struct.STy* [[LOCAL]], i64 0, i32 2 @@ -4077,7 +4077,7 @@ ; IS__TUNIT_NPM-NEXT: ret void ; ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test_nested_memory -; IS__CGSCC_OPM-SAME: (float* nocapture nofree [[DST:%.*]], double* nocapture nofree [[SRC:%.*]]) { +; IS__CGSCC_OPM-SAME: (float* nocapture nofree writeonly [[DST:%.*]], double* nocapture nofree readonly [[SRC:%.*]]) { ; IS__CGSCC_OPM-NEXT: entry: ; IS__CGSCC_OPM-NEXT: [[LOCAL:%.*]] = alloca [[STRUCT_STY:%.*]], align 8 ; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast %struct.STy* [[LOCAL]] to i8* @@ -4094,7 +4094,7 @@ ; IS__CGSCC_OPM-NEXT: ret void ; ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test_nested_memory -; IS__CGSCC_NPM-SAME: (float* nocapture nofree [[DST:%.*]], double* nocapture nofree [[SRC:%.*]]) { +; IS__CGSCC_NPM-SAME: (float* nocapture nofree writeonly [[DST:%.*]], double* nocapture nofree readonly [[SRC:%.*]]) { ; IS__CGSCC_NPM-NEXT: entry: ; IS__CGSCC_NPM-NEXT: [[LOCAL:%.*]] = alloca [[STRUCT_STY:%.*]], align 8 ; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast %struct.STy* [[LOCAL]] to i8*