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 @@ -3086,6 +3086,38 @@ // ------------------------ Align Argument Attribute ------------------------ +static unsigned int getKnownAlignForUse(Attributor &A, + AbstractAttribute &QueryingAA, + Value &AssociatedValue, const Use *U, + const Instruction *I, bool &TrackUse) { + if (ImmutableCallSite ICS = ImmutableCallSite(I)) { + if (ICS.isBundleOperand(U) || ICS.isCallee(U)) + return 0; + + unsigned ArgNo = ICS.getArgumentNo(U); + IRPosition IRP = IRPosition::callsite_argument(ICS, ArgNo); + // As long as we only use known information there is no need to track + // dependences here. + auto &AlignAA = A.getAAFor(QueryingAA, IRP, + /* TrackDependence */ false); + return AlignAA.getKnownAlign(); + } + + // We need to follow common pointer manipulation uses to the accesses they + // feed into. + // TODO: Consider gep instruction + if (isa(I)) { + TrackUse = true; + return 0; + } + + if (auto *SI = dyn_cast(I)) + return SI->getAlignment(); + else if (auto *LI = dyn_cast(I)) + return LI->getAlignment(); + + return 0; +} struct AAAlignImpl : AAAlign { AAAlignImpl(const IRPosition &IRP) : AAAlign(IRP) {} @@ -3143,6 +3175,15 @@ Attrs.emplace_back( Attribute::getWithAlignment(Ctx, Align(getAssumedAlign()))); } + /// See AAFromMustBeExecutedContext + bool followUse(Attributor &A, const Use *U, const Instruction *I) { + bool TrackUse = false; + + unsigned int KnownAlign = getKnownAlignForUse(A, *this, getAssociatedValue(), U, I, TrackUse); + takeKnownMaximum(KnownAlign); + + return TrackUse; + } /// See AbstractAttribute::getAsStr(). const std::string getAsStr() const override { @@ -3153,11 +3194,14 @@ }; /// Align attribute for a floating value. -struct AAAlignFloating : AAAlignImpl { - AAAlignFloating(const IRPosition &IRP) : AAAlignImpl(IRP) {} +struct AAAlignFloating : AAFromMustBeExecutedContext { + using Base = AAFromMustBeExecutedContext; + AAAlignFloating(const IRPosition &IRP) : Base(IRP) {} /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { + Base::updateImpl(A); + const DataLayout &DL = A.getDataLayout(); auto VisitValueCB = [&](Value &V, AAAlign::StateType &T, @@ -3203,9 +3247,12 @@ /// Align attribute for function argument. struct AAAlignArgument final - : AAArgumentFromCallSiteArguments { + : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext { AAAlignArgument(const IRPosition &IRP) - : AAArgumentFromCallSiteArguments(IRP) {} + : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext( + IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(aligned) } @@ -3224,30 +3271,22 @@ }; /// Align attribute deduction for a call site return value. -struct AAAlignCallSiteReturned final : AAAlignImpl { - AAAlignCallSiteReturned(const IRPosition &IRP) : AAAlignImpl(IRP) {} +struct AAAlignCallSiteReturned final + : AACallSiteReturnedFromReturnedAndMustBeExecutedContext { + using Base = + AACallSiteReturnedFromReturnedAndMustBeExecutedContext; + AAAlignCallSiteReturned(const IRPosition &IRP) : Base(IRP) {} /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - AAAlignImpl::initialize(A); + Base::initialize(A); Function *F = getAssociatedFunction(); if (!F) indicatePessimisticFixpoint(); } - /// See AbstractAttribute::updateImpl(...). - ChangeStatus updateImpl(Attributor &A) override { - // TODO: Once we have call site specific value information we can provide - // call site specific liveness information and then it makes - // sense to specialize attributes for call sites arguments instead of - // redirecting requests to the callee argument. - Function *F = getAssociatedFunction(); - const IRPosition &FnPos = IRPosition::returned(*F); - auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), static_cast(FnAA.getState())); - } - /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(align); } }; diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll --- a/llvm/test/Transforms/FunctionAttrs/align.ll +++ b/llvm/test/Transforms/FunctionAttrs/align.ll @@ -330,5 +330,12 @@ ret i32* %phi } + +; ATTRIBUTOR: define i64 @test11(i32* nocapture nofree nonnull readonly align 8 dereferenceable(8) %p) +define i64 @test11(i32* %p) { + %p-cast = bitcast i32* %p to i64* + %ret = load i64, i64* %p-cast, align 8 + ret i64 %ret +} attributes #0 = { nounwind uwtable noinline } attributes #1 = { uwtable noinline } diff --git a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll b/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll --- a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll +++ b/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll @@ -244,7 +244,7 @@ ; } ; ; There should *not* be a no-capture attribute on %a -; CHECK: define nonnull dereferenceable(8) i64* @not_captured_but_returned_0(i64* nofree nonnull returned writeonly dereferenceable(8) "no-capture-maybe-returned" %a) +; CHECK: define nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_0(i64* nofree nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" %a) define i64* @not_captured_but_returned_0(i64* %a) #0 { entry: @@ -260,7 +260,8 @@ ; } ; ; There should *not* be a no-capture attribute on %a -; CHECK: define nonnull dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly dereferenceable(16) "no-capture-maybe-returned" %a) +; FIXME: %a should have align 8 +; CHECK: define nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly dereferenceable(16) "no-capture-maybe-returned" %a) define i64* @not_captured_but_returned_1(i64* %a) #0 { entry: %add.ptr = getelementptr inbounds i64, i64* %a, i64 1 @@ -320,7 +321,7 @@ ; } ; ; There should *not* be a no-capture attribute on %a -; CHECK: define nonnull dereferenceable(8) i64* @negative_test_not_captured_but_returned_call_1a(i64* nofree writeonly "no-capture-maybe-returned" %a) +; CHECK: define nonnull align 8 dereferenceable(8) i64* @negative_test_not_captured_but_returned_call_1a(i64* nofree writeonly "no-capture-maybe-returned" %a) define i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 { entry: %call = call i64* @not_captured_but_returned_1(i64* %a) diff --git a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll --- a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll +++ b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll @@ -254,7 +254,7 @@ ; ; FNATTR: define i32* @rt0(i32* readonly %a) ; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable -; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture nofree nonnull readonly dereferenceable(4) %a) +; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a) define i32* @rt0(i32* %a) #0 { entry: %v = load i32, i32* %a, align 4 @@ -272,7 +272,7 @@ ; ; FNATTR: define noalias i32* @rt1(i32* nocapture readonly %a) ; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable -; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture nofree nonnull readonly dereferenceable(4) %a) +; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a) define i32* @rt1(i32* %a) #0 { entry: %v = load i32, i32* %a, align 4 diff --git a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll --- a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll +++ b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll @@ -189,7 +189,7 @@ } define i32* @f7_3() { -; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @f7_3() +; ATTRIBUTOR: define nonnull align 16 dereferenceable(4) i32* @f7_3() %ptr = tail call i32* @unkown_ptr() store i32 10, i32* %ptr, align 16 ret i32* %ptr diff --git a/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll b/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll --- a/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll +++ b/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll @@ -8,7 +8,7 @@ ret i32 %add } -; CHECK: define private i32 @noalias_args(i32* nocapture nofree nonnull readonly dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly dereferenceable(4) %B) +; CHECK: define private i32 @noalias_args(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) define private i32 @noalias_args(i32* %A, i32* %B) #0 { entry: @@ -23,7 +23,7 @@ ; FIXME: Should be something like this. ; define internal i32 @noalias_args_argmem(i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %B) -; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly dereferenceable(4) %A, i32* nocapture nofree nonnull readonly dereferenceable(4) %B) +; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) ; define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 { diff --git a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll --- a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll +++ b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll @@ -241,31 +241,31 @@ } ; TEST 12 NoFree argument - positive. -; ATTRIBUTOR: define double @test12(double* nocapture nofree nonnull readonly dereferenceable(8) %a) +; ATTRIBUTOR: define double @test12(double* nocapture nofree nonnull readonly align 8 dereferenceable(8) %a) define double @test12(double* nocapture readonly %a) { entry: - %0 = load double, double* %a, align 8 - %call = tail call double @cos(double %0) #2 - ret double %call + %0 = load double, double* %a, align 8 + %call = tail call double @cos(double %0) #2 + ret double %call } declare double @cos(double) nobuiltin nounwind nofree ; FIXME: %a should be nofree. ; TEST 13 NoFree argument - positive. -; ATTRIBUTOR: define noalias i32* @test13(i64* nocapture nonnull readonly dereferenceable(8) %a) +; ATTRIBUTOR: define noalias i32* @test13(i64* nocapture nonnull readonly align 8 dereferenceable(8) %a) define noalias i32* @test13(i64* nocapture readonly %a) { entry: - %0 = load i64, i64* %a, align 8 - %call = tail call noalias i8* @malloc(i64 %0) #2 - %1 = bitcast i8* %call to i32* - ret i32* %1 + %0 = load i64, i64* %a, align 8 + %call = tail call noalias i8* @malloc(i64 %0) #2 + %1 = bitcast i8* %call to i32* + ret i32* %1 } ; ATTRIBUTOR: define void @test14(i8* nocapture %0, i8* nocapture nofree readnone %1) define void @test14(i8* nocapture %0, i8* nocapture %1) { - tail call void @free(i8* %0) #1 - ret void + tail call void @free(i8* %0) #1 + ret void } declare noalias i8* @malloc(i64) diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/FunctionAttrs/nosync.ll --- a/llvm/test/Transforms/FunctionAttrs/nosync.ll +++ b/llvm/test/Transforms/FunctionAttrs/nosync.ll @@ -45,7 +45,7 @@ ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable ; FNATTR-NEXT: define i32 @load_monotonic(i32* nocapture readonly %0) ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable -; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture nofree nonnull readonly dereferenceable(4) %0) +; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0) define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable { %2 = load atomic i32, i32* %0 monotonic, align 4 ret i32 %2 @@ -61,7 +61,7 @@ ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable ; FNATTR-NEXT: define void @store_monotonic(i32* nocapture %0) ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable -; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture nofree nonnull writeonly dereferenceable(4) %0) +; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0) define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable { store atomic i32 10, i32* %0 monotonic, align 4 ret void @@ -78,7 +78,7 @@ ; FNATTR-NEXT: define i32 @load_acquire(i32* nocapture readonly %0) ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable ; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture nofree nonnull readonly dereferenceable(4) %0) +; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0) define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable { %2 = load atomic i32, i32* %0 acquire, align 4 ret i32 %2 @@ -94,7 +94,7 @@ ; FNATTR-NEXT: define void @load_release(i32* nocapture %0) ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable ; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture nofree writeonly %0) +; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture nofree writeonly align 4 %0) define void @load_release(i32* nocapture %0) norecurse nounwind uwtable { store atomic volatile i32 10, i32* %0 release, align 4 ret void @@ -106,7 +106,7 @@ ; FNATTR-NEXT: define void @load_volatile_release(i32* nocapture %0) ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable ; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture nofree writeonly %0) +; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture nofree writeonly align 4 %0) define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable { store atomic volatile i32 10, i32* %0 release, align 4 ret void @@ -122,7 +122,7 @@ ; FNATTR-NEXT: define void @volatile_store(i32* %0) ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable ; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @volatile_store(i32* nofree %0) +; ATTRIBUTOR-NEXT: define void @volatile_store(i32* nofree align 4 %0) define void @volatile_store(i32* %0) norecurse nounwind uwtable { store volatile i32 14, i32* %0, align 4 ret void @@ -139,7 +139,7 @@ ; FNATTR-NEXT: define i32 @volatile_load(i32* %0) ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable ; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32* nofree %0) +; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32* nofree align 4 %0) define i32 @volatile_load(i32* %0) norecurse nounwind uwtable { %2 = load volatile i32, i32* %0, align 4 ret i32 %2 @@ -224,7 +224,7 @@ ; FNATTR: Function Attrs: nofree norecurse nounwind ; FNATTR-NEXT: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1) ; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR: define void @foo1(i32* nocapture nofree nonnull writeonly dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1) +; ATTRIBUTOR: define void @foo1(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1) define void @foo1(i32* %0, %"struct.std::atomic"* %1) { store i32 100, i32* %0, align 4 @@ -257,7 +257,7 @@ ; FNATTR: Function Attrs: nofree norecurse nounwind ; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1) ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind willreturn -; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture nofree nonnull writeonly dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1) +; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1) define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) { store i32 100, i32* %0, align 4 diff --git a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll --- a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll +++ b/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll @@ -70,7 +70,7 @@ } ; CHECK: Function Attrs: nofree nosync nounwind -; CHECK-NEXT: define internal i32* @internal_ret1_rrw(i32* nofree nonnull dereferenceable(4) %r0, i32* nofree returned %r1, i32* nofree %w0) +; CHECK-NEXT: define internal i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) %r0, i32* nofree returned %r1, i32* nofree %w0) define internal i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) { entry: %0 = load i32, i32* %r0, align 4 @@ -121,7 +121,7 @@ } ; CHECK: Function Attrs: nofree nosync nounwind -; CHECK-NEXT: define internal i32* @internal_ret1_rw(i32* nofree nonnull dereferenceable(4) %r0, i32* nofree returned %w0) +; CHECK-NEXT: define internal i32* @internal_ret1_rw(i32* nofree nonnull align 4 dereferenceable(4) %r0, i32* nofree returned %w0) define internal i32* @internal_ret1_rw(i32* %r0, i32* %w0) { entry: %0 = load i32, i32* %r0, align 4 diff --git a/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll --- a/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll +++ b/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll @@ -8,7 +8,7 @@ define <4 x double> @PR21780(double* %ptr) { ; CHECK-LABEL: @PR21780(double* %ptr) -; ATTRIBUTOR-LABEL: @PR21780(double* nocapture nofree nonnull readonly dereferenceable(32) %ptr) +; ATTRIBUTOR-LABEL: @PR21780(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr) ; GEP of index 0 is simplified away. %arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1 @@ -31,6 +31,7 @@ define double @PR21780_only_access3_with_inbounds(double* %ptr) { ; CHECK-LABEL: @PR21780_only_access3_with_inbounds(double* %ptr) +; FIXME: %ptr should have align 8 ; ATTRIBUTOR-LABEL: @PR21780_only_access3_with_inbounds(double* nocapture nofree nonnull readonly dereferenceable(32) %ptr) %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3 @@ -40,6 +41,7 @@ define double @PR21780_only_access3_without_inbounds(double* %ptr) { ; CHECK-LABEL: @PR21780_only_access3_without_inbounds(double* %ptr) +; FIXME: %ptr should have align 8 ; ATTRIBUTOR-LABEL: @PR21780_only_access3_without_inbounds(double* nocapture nofree readonly %ptr) %arrayidx3 = getelementptr double, double* %ptr, i64 3 %t3 = load double, double* %arrayidx3, align 8 @@ -49,7 +51,7 @@ define double @PR21780_without_inbounds(double* %ptr) { ; CHECK-LABEL: @PR21780_without_inbounds(double* %ptr) ; FIXME: this should be @PR21780_without_inbounds(double* nonnull dereferenceable(32) %ptr) -; ATTRIBUTOR-LABEL: @PR21780_without_inbounds(double* nocapture nofree nonnull readonly dereferenceable(8) %ptr) +; ATTRIBUTOR-LABEL: @PR21780_without_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(8) %ptr) %arrayidx1 = getelementptr double, double* %ptr, i64 1 %arrayidx2 = getelementptr double, double* %ptr, i64 2