diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h index bb6298b9aa0e74..7072e949a0703b 100644 --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -4853,21 +4853,13 @@ struct AAPointerInfo : public AbstractAttribute { virtual bool forallInterferingAccesses( OffsetAndSize OAS, function_ref CB) const = 0; - /// Call \p CB on all accesses that might interfere with \p LI and return true - /// if all such accesses were known and the callback returned true for all of - /// them, false otherwise. - virtual bool forallInterferingAccesses( - LoadInst &LI, function_ref CB) const = 0; - virtual bool forallInterferingAccesses( - StoreInst &SI, function_ref CB) const = 0; - - /// Call \p CB on all write accesses that might interfere with \p LI and + /// Call \p CB on all accesses that might interfere with \p I and /// return true if all such accesses were known and the callback returned true /// for all of them, false otherwise. In contrast to forallInterferingAccesses /// this function will perform reasoning to exclude write accesses that cannot /// affect the load even if they on the surface look as if they would. - virtual bool forallInterferingWrites( - Attributor &A, const AbstractAttribute &QueryingAA, LoadInst &LI, + virtual bool forallInterferingAccesses( + Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I, function_ref CB) const = 0; /// This function should return true if the type of the \p AA is AAPointerInfo diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 2154a08ce76c65..9f5907a1f131dc 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -384,7 +384,7 @@ bool AA::getPotentialCopiesOfStoredValue( auto &PI = A.getAAFor(QueryingAA, IRPosition::value(*Obj), DepClassTy::NONE); - if (!PI.forallInterferingAccesses(SI, CheckAccess)) { + if (!PI.forallInterferingAccesses(A, QueryingAA, SI, CheckAccess)) { LLVM_DEBUG( dbgs() << "Failed to verify all interfering accesses for underlying object: " diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index 9ccbda74a0d186..9589a99b238b6f 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -73,11 +73,11 @@ static cl::opt MaxPotentialValues( cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues), cl::init(7)); -static cl::opt - MaxInterferingWrites("attributor-max-interfering-writes", cl::Hidden, - cl::desc("Maximum number of interfering writes to " - "check before assuming all might interfere."), - cl::init(6)); +static cl::opt MaxInterferingAccesses( + "attributor-max-interfering-accesses", cl::Hidden, + cl::desc("Maximum number of interfering accesses to " + "check before assuming all might interfere."), + cl::init(6)); STATISTIC(NumAAs, "Number of abstract attributes created"); @@ -1088,22 +1088,12 @@ struct AAPointerInfoImpl return State::forallInterferingAccesses(OAS, CB); } bool forallInterferingAccesses( - LoadInst &LI, function_ref CB) - const override { - return State::forallInterferingAccesses(LI, CB); - } - bool forallInterferingAccesses( - StoreInst &SI, function_ref CB) - const override { - return State::forallInterferingAccesses(SI, CB); - } - bool forallInterferingWrites( - Attributor &A, const AbstractAttribute &QueryingAA, LoadInst &LI, + Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I, function_ref UserCB) const override { SmallPtrSet DominatingWrites; - SmallVector, 8> InterferingWrites; + SmallVector, 8> InterferingAccesses; - Function &Scope = *LI.getFunction(); + Function &Scope = *I.getFunction(); const auto &NoSyncAA = A.getAAFor( QueryingAA, IRPosition::function(Scope), DepClassTy::OPTIONAL); const auto *ExecDomainAA = A.lookupAAFor( @@ -1131,13 +1121,15 @@ struct AAPointerInfoImpl // TODO: Use inter-procedural reachability and dominance. const auto &NoRecurseAA = A.getAAFor( - QueryingAA, IRPosition::function(*LI.getFunction()), - DepClassTy::OPTIONAL); + QueryingAA, IRPosition::function(Scope), DepClassTy::OPTIONAL); - const bool CanUseCFGResoning = CanIgnoreThreading(LI); + const bool FindInterferingWrites = I.mayReadFromMemory(); + const bool FindInterferingReads = I.mayWriteToMemory(); + const bool UseDominanceReasoning = FindInterferingWrites; + const bool CanUseCFGResoning = CanIgnoreThreading(I); InformationCache &InfoCache = A.getInfoCache(); const DominatorTree *DT = - NoRecurseAA.isKnownNoRecurse() + NoRecurseAA.isKnownNoRecurse() && UseDominanceReasoning ? InfoCache.getAnalysisResultForFunction( Scope) : nullptr; @@ -1193,33 +1185,37 @@ struct AAPointerInfoImpl } auto AccessCB = [&](const Access &Acc, bool Exact) { - if (!Acc.isWrite()) + if ((!FindInterferingWrites || !Acc.isWrite()) && + (!FindInterferingReads || !Acc.isRead())) return true; // For now we only filter accesses based on CFG reasoning which does not // work yet if we have threading effects, or the access is complicated. if (CanUseCFGResoning) { - if (!AA::isPotentiallyReachable(A, *Acc.getLocalInst(), LI, QueryingAA, - IsLiveInCalleeCB)) + if ((!Acc.isWrite() || + !AA::isPotentiallyReachable(A, *Acc.getLocalInst(), I, QueryingAA, + IsLiveInCalleeCB)) && + (!Acc.isRead() || + !AA::isPotentiallyReachable(A, I, *Acc.getLocalInst(), QueryingAA, + IsLiveInCalleeCB))) return true; - if (DT && Exact && - (Acc.getLocalInst()->getFunction() == LI.getFunction()) && + if (DT && Exact && (Acc.getLocalInst()->getFunction() == &Scope) && IsSameThreadAsLoad(Acc)) { - if (DT->dominates(Acc.getLocalInst(), &LI)) + if (DT->dominates(Acc.getLocalInst(), &I)) DominatingWrites.insert(&Acc); } } - InterferingWrites.push_back({&Acc, Exact}); + InterferingAccesses.push_back({&Acc, Exact}); return true; }; - if (!State::forallInterferingAccesses(LI, AccessCB)) + if (!State::forallInterferingAccesses(I, AccessCB)) return false; // If we cannot use CFG reasoning we only filter the non-write accesses // and are done here. if (!CanUseCFGResoning) { - for (auto &It : InterferingWrites) + for (auto &It : InterferingAccesses) if (!UserCB(*It.first, It.second)) return false; return true; @@ -1246,11 +1242,11 @@ struct AAPointerInfoImpl return false; }; - // Run the user callback on all writes we cannot skip and return if that + // Run the user callback on all accesses we cannot skip and return if that // succeeded for all or not. - unsigned NumInterferingWrites = InterferingWrites.size(); - for (auto &It : InterferingWrites) { - if (!DT || NumInterferingWrites > MaxInterferingWrites || + unsigned NumInterferingAccesses = InterferingAccesses.size(); + for (auto &It : InterferingAccesses) { + if (!DT || NumInterferingAccesses > MaxInterferingAccesses || !CanSkipAccess(*It.first, It.second)) { if (!UserCB(*It.first, It.second)) return false; @@ -5464,7 +5460,7 @@ struct AAValueSimplifyImpl : AAValueSimplify { auto &PI = A.getAAFor(AA, IRPosition::value(*Obj), DepClassTy::REQUIRED); - if (!PI.forallInterferingWrites(A, AA, L, CheckAccess)) + if (!PI.forallInterferingAccesses(A, AA, L, CheckAccess)) return false; } return true; diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll index 0b946d41f008ce..a5a0fd27898dc7 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll @@ -76,7 +76,7 @@ entry: ;. ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind readonly willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nounwind readonly willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nosync nounwind readonly willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll index 753463f0480044..9f3a6a623223b4 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll @@ -85,5 +85,5 @@ entry: ;. ; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind readonly willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR2]] = { nounwind readonly willreturn } +; IS__CGSCC____: attributes #[[ATTR2]] = { nosync nounwind readonly willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll index 487c5b79d69b06..6f130bb96ca743 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll @@ -78,5 +78,5 @@ define i32 @callercaller() { ; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn writeonly } -; IS__CGSCC____: attributes #[[ATTR3]] = { nounwind willreturn writeonly } +; IS__CGSCC____: attributes #[[ATTR3]] = { nosync nounwind willreturn writeonly } ;. diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll index 491e3ed4a634fa..76bb6ec8dca95d 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll @@ -92,7 +92,7 @@ define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 { ; IS__CGSCC____-NEXT: [[W:%.*]] = call i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] ; IS__CGSCC____-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]] ; IS__CGSCC____-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 -; IS__CGSCC____-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]] +; IS__CGSCC____-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR3]] ; IS__CGSCC____-NEXT: br label [[OK:%.*]] ; IS__CGSCC____: OK: ; IS__CGSCC____-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 @@ -139,7 +139,6 @@ declare i32 @__gxx_personality_v0(...) ;. ; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR2]] = { nounwind willreturn } -; IS__CGSCC____: attributes #[[ATTR3]] = { readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR4]] = { nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR2]] = { nosync nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR3]] = { nosync nounwind readnone willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/align.ll b/llvm/test/Transforms/Attributor/align.ll index fafcf673152027..748cc25f9c6610 100644 --- a/llvm/test/Transforms/Attributor/align.ll +++ b/llvm/test/Transforms/Attributor/align.ll @@ -1114,7 +1114,6 @@ define void @align4_caller(i8* %p) { declare void @align4_callee(i8* align(4) %p) - attributes #0 = { nounwind uwtable noinline } attributes #1 = { uwtable noinline } attributes #2 = { null_pointer_is_valid } diff --git a/llvm/test/Transforms/Attributor/internal-noalias.ll b/llvm/test/Transforms/Attributor/internal-noalias.ll index eaf9d7d2ca9aff..3670a4bc530b2c 100644 --- a/llvm/test/Transforms/Attributor/internal-noalias.ll +++ b/llvm/test/Transforms/Attributor/internal-noalias.ll @@ -144,12 +144,17 @@ define i32 @visible_local_2() { } define internal i32 @noalias_args_argmem_rn(i32* %A, i32* %B) #1 { -; CHECK: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind willreturn uwtable -; CHECK-LABEL: define {{[^@]+}}@noalias_args_argmem_rn -; CHECK-SAME: (i32* noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1:[0-9]+]] { -; CHECK-NEXT: [[T0:%.*]] = load i32, i32* [[B]], align 4 -; CHECK-NEXT: store i32 0, i32* [[B]], align 4 -; CHECK-NEXT: ret i32 [[T0]] +; IS__TUNIT____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind willreturn uwtable +; IS__TUNIT____-LABEL: define {{[^@]+}}@noalias_args_argmem_rn +; IS__TUNIT____-SAME: (i32* noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] { +; IS__TUNIT____-NEXT: [[T0:%.*]] = load i32, i32* [[B]], align 4 +; IS__TUNIT____-NEXT: ret i32 [[T0]] +; +; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn uwtable +; IS__CGSCC____-LABEL: define {{[^@]+}}@noalias_args_argmem_rn +; IS__CGSCC____-SAME: (i32* noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] { +; IS__CGSCC____-NEXT: [[T0:%.*]] = load i32, i32* undef, align 4 +; IS__CGSCC____-NEXT: ret i32 undef ; %t0 = load i32, i32* %B, align 4 store i32 0, i32* %B @@ -170,8 +175,7 @@ define i32 @visible_local_3() { ; IS__CGSCC____-SAME: () #[[ATTR3]] { ; IS__CGSCC____-NEXT: [[B:%.*]] = alloca i32, align 4 ; IS__CGSCC____-NEXT: store i32 5, i32* [[B]], align 4 -; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_rn(i32* noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[B]]) #[[ATTR6:[0-9]+]] -; IS__CGSCC____-NEXT: ret i32 [[CALL]] +; IS__CGSCC____-NEXT: ret i32 5 ; %B = alloca i32, align 4 store i32 5, i32* %B, align 4 @@ -194,5 +198,4 @@ attributes #1 = { argmemonly noinline nounwind uwtable willreturn} ; IS__CGSCC____: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR4]] = { nounwind readonly } ; IS__CGSCC____: attributes #[[ATTR5]] = { nosync nounwind readonly } -; IS__CGSCC____: attributes #[[ATTR6]] = { nounwind willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/value-simplify-gpu.ll b/llvm/test/Transforms/Attributor/value-simplify-gpu.ll index 0ed49765575add..be3bb318e23e6f 100644 --- a/llvm/test/Transforms/Attributor/value-simplify-gpu.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-gpu.ll @@ -69,7 +69,6 @@ define internal void @level1Kernel(i32 %C) { ; IS__CGSCC____-NEXT: call void @level2Kernelb() #[[ATTR4]] ; IS__CGSCC____-NEXT: br label [[IF_END]] ; IS__CGSCC____: if.end: -; IS__CGSCC____-NEXT: call void @level2Kernelall_late() #[[ATTR6:[0-9]+]] ; IS__CGSCC____-NEXT: ret void ; entry: @@ -236,7 +235,7 @@ define internal void @level1(i32 %C) { ; IS__CGSCC_OPM-NEXT: call void @level2b(i32* noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) #[[ATTR4]] ; IS__CGSCC_OPM-NEXT: br label [[IF_END]] ; IS__CGSCC_OPM: if.end: -; IS__CGSCC_OPM-NEXT: call void @level2all_late(i32* noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) #[[ATTR7:[0-9]+]] +; IS__CGSCC_OPM-NEXT: call void @level2all_late(i32* noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) #[[ATTR6:[0-9]+]] ; IS__CGSCC_OPM-NEXT: ret void ; ; IS__CGSCC_NPM: Function Attrs: norecurse nosync nounwind @@ -251,10 +250,10 @@ define internal void @level1(i32 %C) { ; IS__CGSCC_NPM-NEXT: call void @level2a(i32 undef) #[[ATTR4]] ; IS__CGSCC_NPM-NEXT: br label [[IF_END:%.*]] ; IS__CGSCC_NPM: if.else: -; IS__CGSCC_NPM-NEXT: call void @level2b(i32 undef) #[[ATTR7:[0-9]+]] +; IS__CGSCC_NPM-NEXT: call void @level2b(i32 undef) #[[ATTR6:[0-9]+]] ; IS__CGSCC_NPM-NEXT: br label [[IF_END]] ; IS__CGSCC_NPM: if.end: -; IS__CGSCC_NPM-NEXT: call void @level2all_late(i32* noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) #[[ATTR8:[0-9]+]] +; IS__CGSCC_NPM-NEXT: call void @level2all_late(i32* noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) #[[ATTR7:[0-9]+]] ; IS__CGSCC_NPM-NEXT: ret void ; entry: @@ -413,8 +412,7 @@ declare dso_local void @use(i32, i32, i32) nosync norecurse nounwind ; IS__CGSCC_OPM: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR4]] = { nounwind } ; IS__CGSCC_OPM: attributes #[[ATTR5]] = { nounwind willreturn writeonly } -; IS__CGSCC_OPM: attributes #[[ATTR6]] = { nounwind readnone } -; IS__CGSCC_OPM: attributes #[[ATTR7]] = { nounwind writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR6]] = { nounwind writeonly } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { norecurse nosync nounwind "kernel" } ; IS__CGSCC_NPM: attributes #[[ATTR1]] = { norecurse nosync nounwind } @@ -422,7 +420,6 @@ declare dso_local void @use(i32, i32, i32) nosync norecurse nounwind ; IS__CGSCC_NPM: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR4]] = { nounwind } ; IS__CGSCC_NPM: attributes #[[ATTR5]] = { nounwind willreturn writeonly } -; IS__CGSCC_NPM: attributes #[[ATTR6]] = { nounwind readnone } -; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nosync nounwind } -; IS__CGSCC_NPM: attributes #[[ATTR8]] = { nosync nounwind writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR6]] = { nosync nounwind } +; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nosync nounwind writeonly } ;.