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 @@ -3119,6 +3119,20 @@ AbstractAttribute &QueryingAA, Value &AssociatedValue, const Use *U, const Instruction *I, bool &TrackUse) { + // We need to follow common pointer manipulation uses to the accesses they + // feed into. + if (isa(I)) { + TrackUse = true; + return 0; + } + if (auto *GEP = dyn_cast(I)) { + if (GEP->hasAllConstantIndices()) { + TrackUse = true; + return 0; + } + } + + unsigned Alignment = 0; if (ImmutableCallSite ICS = ImmutableCallSite(I)) { if (ICS.isBundleOperand(U) || ICS.isCallee(U)) return 0; @@ -3129,23 +3143,34 @@ // 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; + Alignment = AlignAA.getKnownAlign(); } + const Value *UseV = U->get(); if (auto *SI = dyn_cast(I)) - return SI->getAlignment(); + Alignment = SI->getAlignment(); else if (auto *LI = dyn_cast(I)) - return LI->getAlignment(); + Alignment = LI->getAlignment(); - return 0; + if (Alignment <= 1) + return 0; + + auto &DL = A.getDataLayout(); + int64_t Offset; + + if (const Value *Base = GetPointerBaseWithConstantOffset(UseV, Offset, DL)) { + if (Base == &AssociatedValue) { + // BasePointerAddr + Offset = Alignment * Q for some integer Q. + // So we can say that the maximum power of two which is a divisor of + // gcd(Offset, Alignment) is an alignment. + + uint32_t gcd = + greatestCommonDivisor(uint32_t(abs((int32_t)Offset)), Alignment); + Alignment = llvm::PowerOf2Floor(gcd); + } + } + + return Alignment; } struct AAAlignImpl : AAAlign { AAAlignImpl(const IRPosition &IRP) : AAAlign(IRP) {} 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 @@ -337,5 +337,66 @@ %ret = load i64, i64* %p-cast, align 8 ret i64 %ret } + +; TEST 12 +; Test for deduction using must-be-executed-context and GEP instruction + +; FXIME: %p should have nonnull +; ATTRIBUTOR: define i64 @test12-1(i32* nocapture nofree readonly align 16 %p) +define i64 @test12-1(i32* align 4 %p) { + %p-cast = bitcast i32* %p to i64* + %arrayidx0 = getelementptr i64, i64* %p-cast, i64 1 + %arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3 + %ret = load i64, i64* %arrayidx1, align 16 + ret i64 %ret +} + +; FXIME: %p should have nonnull +; ATTRIBUTOR: define i64 @test12-2(i32* nocapture nofree readonly align 16 %p) +define i64 @test12-2(i32* align 4 %p) { + %p-cast = bitcast i32* %p to i64* + %arrayidx0 = getelementptr i64, i64* %p-cast, i64 0 + %ret = load i64, i64* %arrayidx0, align 16 + ret i64 %ret +} + +; FXIME: %p should have nonnull +; ATTRIBUTOR: define void @test12-3(i32* nocapture nofree writeonly align 16 %p) +define void @test12-3(i32* align 4 %p) { + %p-cast = bitcast i32* %p to i64* + %arrayidx0 = getelementptr i64, i64* %p-cast, i64 1 + %arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3 + store i64 0, i64* %arrayidx1, align 16 + ret void +} + +; FXIME: %p should have nonnull +; ATTRIBUTOR: define void @test12-4(i32* nocapture nofree writeonly align 16 %p) +define void @test12-4(i32* align 4 %p) { + %p-cast = bitcast i32* %p to i64* + %arrayidx0 = getelementptr i64, i64* %p-cast, i64 0 + store i64 0, i64* %arrayidx0, align 16 + ret void +} + +declare void @use(i64*) willreturn nounwind + +; ATTRIBUTOR: define void @test12-5(i32* align 16 %p) +define void @test12-5(i32* align 4 %p) { + %p-cast = bitcast i32* %p to i64* + %arrayidx0 = getelementptr i64, i64* %p-cast, i64 1 + %arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3 + tail call void @use(i64* align 16 %arrayidx1) + ret void +} + +; ATTRIBUTOR: define void @test12-6(i32* align 16 %p) +define void @test12-6(i32* align 4 %p) { + %p-cast = bitcast i32* %p to i64* + %arrayidx0 = getelementptr i64, i64* %p-cast, i64 0 + tail call void @use(i64* align 16 %arrayidx0) + ret void +} + 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 @@ -260,8 +260,7 @@ ; } ; ; There should *not* be a no-capture attribute on %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) +; CHECK: define nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 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 diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll --- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll +++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll @@ -259,7 +259,7 @@ } ; FNATTR: define void @test_volatile(i32* %x) -; ATTRIBUTOR: define void @test_volatile(i32* nofree %x) +; ATTRIBUTOR: define void @test_volatile(i32* nofree align 4 %x) define void @test_volatile(i32* %x) { entry: %gep = getelementptr i32, i32* %x, i64 1 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 @@ -31,8 +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) +; ATTRIBUTOR-LABEL: @PR21780_only_access3_with_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr) %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3 %t3 = load double, double* %arrayidx3, align 8 @@ -41,8 +40,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) +; ATTRIBUTOR-LABEL: @PR21780_only_access3_without_inbounds(double* nocapture nofree readonly align 8 %ptr) %arrayidx3 = getelementptr double, double* %ptr, i64 3 %t3 = load double, double* %arrayidx3, align 8 ret double %t3