Index: llvm/lib/Transforms/IPO/AttributorAttributes.cpp =================================================================== --- llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -2427,7 +2427,20 @@ /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { - // TODO: Implement this. + // If an associated value is an local global variable and it is used only once, + // we can deduce noalias for it. + if (auto *GV = dyn_cast(&getAssociatedValue())) { + if (GV->hasLocalLinkage()) { + int LiveUseCount = 0; + auto UsePred = [&](const Use &U, bool &) { + LiveUseCount++; + return LiveUseCount <= 1; + }; + if (A.checkForAllUses(UsePred, *this, getAssociatedValue())) { + return ChangeStatus::UNCHANGED; + } + } + } return indicatePessimisticFixpoint(); } Index: llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll =================================================================== --- llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll +++ llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll @@ -21,7 +21,7 @@ ; CHECK-LABEL: define {{[^@]+}}@main ; CHECK-SAME: (i32 [[ARGC:%.*]], i8** nocapture nofree readnone [[ARGV:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call void (i8*, i8*, i8*, i8*, i8*, ...) @callee_t0f(i8* undef, i8* undef, i8* undef, i8* undef, i8* undef, %struct.tt0* noundef nonnull byval align 8 dereferenceable(16) @t45) +; CHECK-NEXT: tail call void (i8*, i8*, i8*, i8*, i8*, ...) @callee_t0f(i8* undef, i8* undef, i8* undef, i8* undef, i8* undef, %struct.tt0* noalias noundef nonnull byval align 8 dereferenceable(16) @t45) ; CHECK-NEXT: ret i32 0 ; entry: Index: llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll @@ -106,7 +106,7 @@ ; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@unions ; IS__TUNIT_OPM-SAME: () [[ATTR1:#.*]] { ; IS__TUNIT_OPM-NEXT: entry: -; IS__TUNIT_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(%struct.MYstr* nocapture nofree noundef nonnull readonly byval align 8 dereferenceable(8) @mystr) [[ATTR0]] +; IS__TUNIT_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(%struct.MYstr* noalias nocapture nofree noundef nonnull readonly byval align 8 dereferenceable(8) @mystr) [[ATTR0]] ; IS__TUNIT_OPM-NEXT: ret i32 [[RESULT]] ; ; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind willreturn @@ -217,7 +217,7 @@ ; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@unions_v2 ; IS__TUNIT_OPM-SAME: () [[ATTR2]] { ; IS__TUNIT_OPM-NEXT: entry: -; IS__TUNIT_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(%struct.MYstr* nocapture nofree noundef nonnull readonly byval align 8 dereferenceable(8) @mystr) [[ATTR2]] +; IS__TUNIT_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(%struct.MYstr* noalias nocapture nofree noundef nonnull readonly byval align 8 dereferenceable(8) @mystr) [[ATTR2]] ; IS__TUNIT_OPM-NEXT: ret i32 [[RESULT]] ; ; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn 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 @@ -47,7 +47,7 @@ ; IS__TUNIT_NPM-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4 ; IS__TUNIT_NPM-NEXT: store float 3.000000e+00, float* [[P]], align 4 ; IS__TUNIT_NPM-NEXT: store i32 7, i32* [[N_ADDR]], align 4 -; IS__TUNIT_NPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1:@.*]], i32 noundef 3, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[P]], i64 undef) +; IS__TUNIT_NPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noalias noundef nonnull align 8 dereferenceable(24) [[GLOB1:@.*]], i32 noundef 3, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[P]], i64 undef) ; IS__TUNIT_NPM-NEXT: ret void ; ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@foo @@ -69,7 +69,7 @@ ; IS__CGSCC_NPM-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4 ; IS__CGSCC_NPM-NEXT: store float 3.000000e+00, float* [[P]], align 4 ; IS__CGSCC_NPM-NEXT: store i32 7, i32* [[N_ADDR]], align 4 -; IS__CGSCC_NPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1:@.*]], i32 noundef 3, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[P]], i64 noundef 4617315517961601024) +; IS__CGSCC_NPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noalias noundef nonnull align 8 dereferenceable(24) [[GLOB1:@.*]], i32 noundef 3, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) [[P]], i64 noundef 4617315517961601024) ; IS__CGSCC_NPM-NEXT: ret void ; entry: @@ -139,7 +139,7 @@ ; IS________OPM-NEXT: br label [[OMP_LOOP_EXIT:%.*]] ; IS________OPM: omp.loop.exit: ; IS________OPM-NEXT: [[TMP12:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4 -; IS________OPM-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 [[TMP12]]) +; IS________OPM-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* noalias noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 [[TMP12]]) ; IS________OPM-NEXT: br label [[OMP_PRECOND_END]] ; IS________OPM: omp.precond.end: ; IS________OPM-NEXT: ret void @@ -164,7 +164,7 @@ ; IS________NPM-NEXT: store i32 1, i32* [[DOTOMP_STRIDE]], align 4 ; IS________NPM-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST]], align 4 ; IS________NPM-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4 -; IS________NPM-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0:@.*]], i32 [[TMP5]], i32 noundef 34, i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_IS_LAST]], i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_LB]], i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_UB]], i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_STRIDE]], i32 noundef 1, i32 noundef 1) +; IS________NPM-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* noalias noundef nonnull align 8 dereferenceable(24) [[GLOB0:@.*]], i32 [[TMP5]], i32 noundef 34, i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_IS_LAST]], i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_LB]], i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_UB]], i32* noundef nonnull align 4 dereferenceable(4) [[DOTOMP_STRIDE]], i32 noundef 1, i32 noundef 1) ; IS________NPM-NEXT: [[TMP6:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4 ; IS________NPM-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP6]], [[SUB3]] ; IS________NPM-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] @@ -200,7 +200,7 @@ ; IS________NPM-NEXT: br label [[OMP_LOOP_EXIT:%.*]] ; IS________NPM: omp.loop.exit: ; IS________NPM-NEXT: [[TMP12:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4 -; IS________NPM-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 [[TMP12]]) +; IS________NPM-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* noalias noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 [[TMP12]]) ; IS________NPM-NEXT: br label [[OMP_PRECOND_END]] ; IS________NPM: omp.precond.end: ; IS________NPM-NEXT: ret void Index: llvm/test/Transforms/Attributor/misc_crash.ll =================================================================== --- llvm/test/Transforms/Attributor/misc_crash.ll +++ llvm/test/Transforms/Attributor/misc_crash.ll @@ -41,7 +41,7 @@ define internal void @func2a(i32* %0) { ; CHECK: Function Attrs: nofree nosync nounwind willreturn writeonly ; CHECK-LABEL: define {{[^@]+}}@func2a -; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]]) [[ATTR1:#.*]] { +; CHECK-SAME: (i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]]) [[ATTR1:#.*]] { ; CHECK-NEXT: store i32 0, i32* @var2, align 4 ; CHECK-NEXT: ret void ; @@ -51,7 +51,7 @@ define i32 @func2() { ; CHECK-LABEL: define {{[^@]+}}@func2() { -; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* noundef nonnull align 4 dereferenceable(4) @var2) +; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* noalias noundef nonnull align 4 dereferenceable(4) @var2) ; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* @var2, align 4 ; CHECK-NEXT: ret i32 [[TMP2]] ; @@ -63,7 +63,7 @@ define i32 @func3(i1 %false) { ; CHECK-LABEL: define {{[^@]+}}@func3 ; CHECK-SAME: (i1 [[FALSE:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* noundef nonnull align 4 dereferenceable(4) @var2) +; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* noalias noundef nonnull align 4 dereferenceable(4) @var2) ; CHECK-NEXT: br i1 [[FALSE]], label [[USE_BB:%.*]], label [[RET_BB:%.*]] ; CHECK: use_bb: ; CHECK-NEXT: ret i32 [[TMP1]]