Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -844,7 +844,8 @@ /// This method will evaluate \p Pred on all (transitive) uses of the /// associated value and return true if \p Pred holds every time. bool checkForAllUses(const function_ref &Pred, - const AbstractAttribute &QueryingAA, const Value &V); + const AbstractAttribute &QueryingAA, const Value &V, + const Instruction *ReachableFromI = nullptr); /// Check \p Pred on all function call sites. /// Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -2298,15 +2298,30 @@ << " is assumed NoAlias in the definition\n"); // (ii) Check whether the value is captured in the scope using AANoCapture. - // FIXME: This is conservative though, it is better to look at CFG and - // check only uses possibly executed before this callsite. + // Look at CFG and check only uses possibly executed before this + // callsite. + + auto UsePred = [&](const Use &U, bool &Follow) -> bool { + if (isa(U) || isa(U) || isa(U) || + isa(U)) { + Follow = true; + return true; + } + + // Unknown user for which we can not track uses further + LLVM_DEBUG(dbgs() << "[Attributor][AANoAliasCSArg] Unknown user: " << *U + << "\n"); + return false; + }; auto &NoCaptureAA = A.getAAFor(*this, IRP); if (!NoCaptureAA.isAssumedNoCaptureMaybeReturned()) { - LLVM_DEBUG( - dbgs() << "[Attributor][AANoAliasCSArg] " << V - << " cannot be noalias as it is potentially captured\n"); - return indicatePessimisticFixpoint(); + if (!A.checkForAllUses(UsePred, *this, V, getCtxI())) { + LLVM_DEBUG( + dbgs() << "[Attributor][AANoAliasCSArg] " << V + << " cannot be noalias as it is potentially captured\n"); + return indicatePessimisticFixpoint(); + } } // (iii) Check there is no other pointer argument which could alias with the @@ -5006,7 +5021,8 @@ bool Attributor::checkForAllUses( const function_ref &Pred, - const AbstractAttribute &QueryingAA, const Value &V) { + const AbstractAttribute &QueryingAA, const Value &V, + const Instruction *ReachableFromI) { const IRPosition &IRP = QueryingAA.getIRPosition(); SmallVector Worklist; SmallPtrSet Visited; @@ -5027,12 +5043,18 @@ /* TrackDependence */ false) : nullptr; + const auto *ReachabilityAA = + ScopeFn ? &getAAFor(QueryingAA, + IRPosition::function(*ScopeFn), + /* TrackDependence */ false) + : nullptr; + while (!Worklist.empty()) { const Use *U = Worklist.pop_back_val(); if (!Visited.insert(U).second) continue; LLVM_DEBUG(dbgs() << "[Attributor] Check use: " << **U << "\n"); - if (Instruction *UserI = dyn_cast(U->getUser())) + if (Instruction *UserI = dyn_cast(U->getUser())) { if (LivenessAA && LivenessAA->isAssumedDead(UserI)) { LLVM_DEBUG(dbgs() << "[Attributor] Dead user: " << *UserI << ": " << *LivenessAA << "\n"); @@ -5040,6 +5062,14 @@ continue; } + // For uses which reachable call instruction. + if (ReachableFromI) { + if (ReachabilityAA->isAssumedReachable(UserI, ReachableFromI)) + return true; + continue; + } + } + bool Follow = false; if (!Pred(*U, Follow)) return false; Index: llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll =================================================================== --- llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll +++ llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll @@ -29,7 +29,7 @@ ; Function Attrs: nounwind uwtable define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture readnone %tp14, i8* nocapture readnone %tp15, i8* nocapture readnone %tp16, i8* nocapture readnone %tp17, ...) { ; CHECK-LABEL: define {{[^@]+}}@callee_t0f -; CHECK-SAME: (i8* nocapture nofree nonnull readnone [[TP13:%.*]], i8* nocapture nofree nonnull readnone [[TP14:%.*]], i8* nocapture nofree nonnull readnone [[TP15:%.*]], i8* nocapture nofree nonnull readnone [[TP16:%.*]], i8* nocapture nofree nonnull readnone [[TP17:%.*]], ...) +; CHECK-SAME: (i8* noalias nocapture nofree nonnull readnone [[TP13:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP14:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP15:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP16:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP17:%.*]], ...) ; CHECK-NEXT: entry: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll @@ -33,7 +33,7 @@ ; CHECK-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4 ; CHECK-NEXT: store float 3.000000e+00, float* [[P]], align 4 ; CHECK-NEXT: store i32 7, i32* [[N_ADDR]], align 4 -; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @1, i32 3, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* nonnull align 4 dereferenceable(4) [[N_ADDR]], float* nonnull align 4 dereferenceable(4) [[P]], i64 4617315517961601024) +; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @1, i32 3, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nonnull align 4 dereferenceable(4) [[N_ADDR]], float* noalias nonnull align 4 dereferenceable(4) [[P]], i64 4617315517961601024) ; CHECK-NEXT: ret void ; entry: Index: llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll @@ -33,10 +33,10 @@ ; CHECK-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8 ; CHECK-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8 ; CHECK-NEXT: [[THREAD:%.*]] = alloca i64, align 8 -; CHECK-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @foo, i8* noalias null) -; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @bar, i8* nonnull align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*)) -; CHECK-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nonnull align 8 dereferenceable(1) [[ALLOC1]]) -; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @buz, i8* nonnull align 8 dereferenceable(1) [[ALLOC2]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* noalias nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @foo, i8* noalias null) +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* noalias nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @bar, i8* nonnull align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*)) +; CHECK-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* noalias nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nonnull align 8 dereferenceable(1) [[ALLOC1]]) +; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* noalias nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @buz, i8* noalias nonnull align 8 dereferenceable(1) [[ALLOC2]]) ; CHECK-NEXT: ret i32 0 ; entry: @@ -84,7 +84,7 @@ define internal i8* @buz(i8* %arg) { ; CHECK-LABEL: define {{[^@]+}}@buz -; CHECK-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]]) +; CHECK-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i8* [[ARG:%.*]] ; Index: llvm/test/Transforms/Attributor/callbacks.ll =================================================================== --- llvm/test/Transforms/Attributor/callbacks.ll +++ llvm/test/Transforms/Attributor/callbacks.ll @@ -24,7 +24,7 @@ ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* ; CHECK-NEXT: store i32 42, i32* [[B]], align 32 ; CHECK-NEXT: store i32* [[B]], i32** [[C]], align 64 -; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* [[A:%.*]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]]) +; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* [[A:%.*]], i64 99, i32** noalias nonnull align 64 dereferenceable(8) [[C]]) ; CHECK-NEXT: ret void ; entry: Index: llvm/test/Transforms/Attributor/heap_to_stack.ll =================================================================== --- llvm/test/Transforms/Attributor/heap_to_stack.ll +++ llvm/test/Transforms/Attributor/heap_to_stack.ll @@ -48,7 +48,7 @@ define void @test2() { %1 = tail call noalias i8* @malloc(i64 4) ; CHECK: @malloc(i64 4) - ; CHECK-NEXT: @sync_func(i8* %1) + ; CHECK-NEXT: @sync_func(i8* noalias %1) tail call void @sync_func(i8* %1) tail call void @free(i8* %1) ret void @@ -164,13 +164,13 @@ define void @test8() { %1 = tail call noalias i8* @malloc(i64 4) ; CHECK: %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) + ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) tail call void @no_sync_func(i8* %1) %2 = bitcast i8* %1 to i32* store i32 10, i32* %2 %3 = load i32, i32* %2 tail call void @foo(i32* %2) - ; CHECK: @free(i8* %1) + ; CHECK: @free(i8* noalias %1) tail call void @free(i8* %1) ret void } @@ -179,13 +179,13 @@ define void @test9() { %1 = tail call noalias i8* @malloc(i64 4) ; CHECK: %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) + ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) tail call void @no_sync_func(i8* %1) %2 = bitcast i8* %1 to i32* store i32 10, i32* %2 %3 = load i32, i32* %2 tail call void @foo_nounw(i32* %2) - ; CHECK: @free(i8* %1) + ; CHECK: @free(i8* noalias %1) tail call void @free(i8* %1) ret void } @@ -225,7 +225,7 @@ %1 = tail call noalias i8* @malloc(i64 4) ; CHECK: test11 ; CHECK-NEXT: alloc - ; CHECK-NEXT: @sync_will_return(i8* %1) + ; CHECK-NEXT: @sync_will_return(i8* noalias %1) tail call void @sync_will_return(i8* %1) tail call void @free(i8* %1) ret void @@ -374,9 +374,9 @@ %1 = tail call noalias i8* @malloc(i64 4) ; CHECK-NEXT: store i8* %1, i8** %P store i8* %1, i8** %P - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) + ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) tail call void @no_sync_func(i8* %1) - ; CHECK-NEXT: @free(i8* %1) + ; CHECK-NEXT: @free(i8* noalias %1) tail call void @free(i8* %1) ret void } @@ -386,7 +386,7 @@ %1 = tail call noalias i8* @malloc(i64 4) ; CHECK-NEXT: store i8* %1, i8** %P store i8* %1, i8** %P - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) + ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) tail call void @no_sync_func(i8* %1) nounwind ; CHECK-NOT: @free tail call void @free(i8* %1) Index: llvm/test/Transforms/Attributor/misc.ll =================================================================== --- llvm/test/Transforms/Attributor/misc.ll +++ llvm/test/Transforms/Attributor/misc.ll @@ -10,7 +10,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) +; CHECK-NEXT: call void @foo(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) undef) ; CHECK-NEXT: call void [[FP:%.*]](i8* bitcast (void (i32*)* @foo to i8*)) ; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) @@ -24,7 +24,7 @@ ; DECL_CS-NEXT: entry: ; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 ; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) +; DECL_CS-NEXT: call void @foo(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) undef) ; DECL_CS-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) ; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*)) @@ -52,7 +52,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) +; CHECK-NEXT: call void @foo(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) undef) ; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) ; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]]) @@ -67,7 +67,7 @@ ; DECL_CS-NEXT: entry: ; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 ; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) +; DECL_CS-NEXT: call void @foo(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) undef) ; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*)) ; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]]) Index: llvm/test/Transforms/Attributor/noalias.ll =================================================================== --- llvm/test/Transforms/Attributor/noalias.ll +++ llvm/test/Transforms/Attributor/noalias.ll @@ -168,14 +168,14 @@ declare void @test10_helper_1(i8* %a) define void @test10_helper_2(i8* noalias %a) { -; CHECK: tail call void @test10_helper_1(i8* %a) +; CHECK: tail call void @test10_helper_1(i8* noalias %a) tail call void @test10_helper_1(i8* %a) ret void } define void @test10(i8* noalias %a) { ; CHECK: define void @test10(i8* noalias %a) ; FIXME: missing noalias -; CHECK-NEXT: tail call void @test10_helper_1(i8* %a) +; CHECK-NEXT: tail call void @test10_helper_1(i8* noalias %a) tail call void @test10_helper_1(i8* %a) ; CHECK-NEXT: tail call void @test10_helper_2(i8* noalias %a) @@ -222,11 +222,11 @@ ; CHECK-LABEL: @test12_2( ; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4) ; FIXME: This should be @use_nocapture(i8* noalias [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]]) ; FIXME: This should be @use_nocapture(i8* noalias nocapture [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) -; CHECK-NEXT: tail call void @use(i8* [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]]) +; CHECK-NEXT: tail call void @use(i8* noalias [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]]) ; CHECK-NEXT: ret void ; %A = tail call noalias i8* @malloc(i64 4)