diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -729,6 +729,17 @@ ConstantInt *CI = mdconst::extract(MD->getOperand(0)); return MaybeAlign(CI->getLimitedValue()); } + } else if (auto *CstPtr = dyn_cast(this)) { + if (auto *CstInt = dyn_cast_or_null(ConstantExpr::getPtrToInt( + const_cast(CstPtr), DL.getIntPtrType(getType()), + /*OnlyIfReduced=*/true))) { + size_t TrailingZeros = CstInt->getValue().countTrailingZeros(); + // While the actual alignment may be large, elsewhere we have + // an arbitrary upper alignmet limit, so let's clamp to it. + return Align(TrailingZeros < Value::MaxAlignmentExponent + ? uint64_t(1) << TrailingZeros + : Value::MaximumAlignment); + } } return llvm::None; } diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll @@ -6,9 +6,9 @@ ; because there is a load of %A in the entry block define internal i32 @callee(i1 %C, i32* %A) { ; CHECK-LABEL: define {{[^@]+}}@callee -; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree nonnull readonly dereferenceable(4) [[A:%.*]]) +; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree nonnull readonly align 536870912 dereferenceable(4) [[A:%.*]]) ; CHECK-NEXT: entry: -; CHECK-NEXT: [[A_0:%.*]] = load i32, i32* null +; CHECK-NEXT: [[A_0:%.*]] = load i32, i32* null, align 536870912 ; CHECK-NEXT: br label [[F:%.*]] ; CHECK: T: ; CHECK-NEXT: unreachable @@ -34,7 +34,7 @@ define i32 @foo() { ; CHECK-LABEL: define {{[^@]+}}@foo() -; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 false, i32* noalias nofree readonly null) +; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 false, i32* noalias nofree readonly align 536870912 null) ; CHECK-NEXT: ret i32 [[X]] ; %X = call i32 @callee(i1 false, i32* null) ; [#uses=1] diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll +++ b/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 nofree readnone 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* nofree nonnull readnone 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 nofree nonnull readnone 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* nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null) +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* nofree nonnull readnone 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 align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]]) +; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]]) ; CHECK-NEXT: ret i32 0 ; entry: @@ -54,7 +54,7 @@ define internal i8* @foo(i8* %arg) { ; CHECK-LABEL: define {{[^@]+}}@foo -; CHECK-SAME: (i8* noalias nofree readnone returned [[ARG:%.*]]) +; CHECK-SAME: (i8* noalias nofree readnone returned align 536870912 [[ARG:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i8* null ; diff --git a/llvm/test/Transforms/Attributor/align.ll b/llvm/test/Transforms/Attributor/align.ll --- a/llvm/test/Transforms/Attributor/align.ll +++ b/llvm/test/Transforms/Attributor/align.ll @@ -398,6 +398,30 @@ ret void } +define void @test13(i1 %c, i32* align 32 %dst) #0 { +; ATTRIBUTOR-LABEL: define {{[^@]+}}@test13 +; ATTRIBUTOR-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]]) +; ATTRIBUTOR-NEXT: br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]] +; ATTRIBUTOR: truebb: +; ATTRIBUTOR-NEXT: br label [[END:%.*]] +; ATTRIBUTOR: falsebb: +; ATTRIBUTOR-NEXT: br label [[END]] +; ATTRIBUTOR: end: +; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ null, [[FALSEBB]] ] +; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 32 +; ATTRIBUTOR-NEXT: ret void +; + br i1 %c, label %truebb, label %falsebb +truebb: + br label %end +falsebb: + br label %end +end: + %ptr = phi i32* [ %dst, %truebb ], [ null, %falsebb ] + store i32 0, i32* %ptr + ret void +} + ; Don't crash on ptr2int/int2ptr uses. define i64 @ptr2int(i32* %p) { %p2i = ptrtoint i32* %p to i64 @@ -410,3 +434,4 @@ attributes #0 = { nounwind uwtable noinline } attributes #1 = { uwtable noinline } +attributes #2 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/Attributor/callbacks.ll b/llvm/test/Transforms/Attributor/callbacks.ll --- a/llvm/test/Transforms/Attributor/callbacks.ll +++ b/llvm/test/Transforms/Attributor/callbacks.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes ; FIXME: Add -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations below. ; This flag was removed because max iterations is 2 in most cases, but in windows it is 1. ; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-annotate-decl-cs < %s | FileCheck %s @@ -15,7 +15,8 @@ ; transfer in both directions. define void @t0_caller(i32* %a) { -; CHECK-LABEL: @t0_caller( +; CHECK-LABEL: define {{[^@]+}}@t0_caller +; CHECK-SAME: (i32* align 256 [[A:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = alloca i32, align 32 ; CHECK-NEXT: [[C:%.*]] = alloca i32*, align 64 @@ -23,10 +24,10 @@ ; 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* align 256 [[A:%.*]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) - +; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias align 536870912 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* align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) ; CHECK-NEXT: ret void ; + entry: %b = alloca i32, align 32 %c = alloca i32*, align 64 @@ -44,10 +45,10 @@ ; CHECK-LABEL: define {{[^@]+}}@t0_callback_callee ; CHECK-SAME: (i32* nocapture nonnull writeonly dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) ; CHECK-NEXT: entry: -; CHECK-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR:%.*]], align 8 -; CHECK-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL:%.*]] -; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C:%.*]], align 64 -; CHECK-NEXT: tail call void @t0_check(i32* align 256 [[A:%.*]], i64 99, i32* [[TMP0]]) +; CHECK-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 +; CHECK-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]] +; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 +; CHECK-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]]) ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/Attributor/nocapture-1.ll b/llvm/test/Transforms/Attributor/nocapture-1.ll --- a/llvm/test/Transforms/Attributor/nocapture-1.ll +++ b/llvm/test/Transforms/Attributor/nocapture-1.ll @@ -322,7 +322,7 @@ define void @test_callsite() { entry: ; We know that 'null' in AS 0 does not alias anything and cannot be captured. Though the latter is not qurried -> derived atm. -; ATTRIBUTOR: call void @unknown(i8* noalias null) +; ATTRIBUTOR: call void @unknown(i8* noalias align 536870912 null) call void @unknown(i8* null) ret void } diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll --- a/llvm/test/Transforms/Attributor/nonnull.ll +++ b/llvm/test/Transforms/Attributor/nonnull.ll @@ -23,7 +23,7 @@ ; Given an SCC where one of the functions can not be marked nonnull, ; can we still mark the other one which is trivially nonnull define i8* @scc_binder(i1 %c) { -; ATTRIBUTOR: define noalias i8* @scc_binder +; ATTRIBUTOR: define noalias align 536870912 i8* @scc_binder br i1 %c, label %rec, label %end rec: call i8* @test3(i1 %c) @@ -57,7 +57,7 @@ ; Given a mutual recursive set of functions which *can* return null ; make sure we haven't marked them as nonnull. define i8* @test5_helper(i1 %c) { -; ATTRIBUTOR: define noalias i8* @test5_helper +; ATTRIBUTOR: define noalias align 536870912 i8* @test5_helper br i1 %c, label %rec, label %end rec: %ret = call i8* @test5(i1 %c) @@ -67,7 +67,7 @@ } define i8* @test5(i1 %c) { -; ATTRIBUTOR: define noalias i8* @test5 +; ATTRIBUTOR: define noalias align 536870912 i8* @test5 %ret = call i8* @test5_helper(i1 %c) ret i8* %ret } @@ -525,7 +525,7 @@ ret i32 addrspace(3)* %p } -; ATTRIBUTOR: define internal nonnull i32* @g2() +; ATTRIBUTOR: define internal nonnull align 4 i32* @g2() define internal i32* @g2() { ret i32* inttoptr (i64 4 to i32*) } diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -194,14 +194,14 @@ %struct.X = type { i8* } define internal i32* @test_inalloca(i32* inalloca %a) { ; CHECK-LABEL: define {{[^@]+}}@test_inalloca -; CHECK-SAME: (i32* inalloca noalias nofree returned writeonly [[A:%.*]]) +; CHECK-SAME: (i32* inalloca noalias nofree returned writeonly align 536870912 [[A:%.*]]) ; CHECK-NEXT: ret i32* [[A]] ; ret i32* %a } define i32* @complicated_args_inalloca() { ; CHECK-LABEL: define {{[^@]+}}@complicated_args_inalloca() -; CHECK-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree writeonly null) +; CHECK-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree writeonly align 536870912 null) ; CHECK-NEXT: ret i32* [[CALL]] ; %call = call i32* @test_inalloca(i32* null) @@ -210,7 +210,7 @@ define internal void @test_sret(%struct.X* sret %a, %struct.X** %b) { ; CHECK-LABEL: define {{[^@]+}}@test_sret -; CHECK-SAME: (%struct.X* nofree sret writeonly [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly dereferenceable(8) [[B:%.*]]) +; CHECK-SAME: (%struct.X* nofree sret writeonly align 536870912 [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly dereferenceable(8) [[B:%.*]]) ; CHECK-NEXT: store %struct.X* [[A]], %struct.X** [[B]] ; CHECK-NEXT: ret void ; @@ -220,7 +220,7 @@ define void @complicated_args_sret(%struct.X** %b) { ; CHECK-LABEL: define {{[^@]+}}@complicated_args_sret ; CHECK-SAME: (%struct.X** nocapture nofree writeonly [[B:%.*]]) -; CHECK-NEXT: call void @test_sret(%struct.X* nofree writeonly null, %struct.X** nocapture nofree writeonly [[B]]) +; CHECK-NEXT: call void @test_sret(%struct.X* nofree writeonly align 536870912 null, %struct.X** nocapture nofree writeonly [[B]]) ; CHECK-NEXT: ret void ; call void @test_sret(%struct.X* null, %struct.X** %b) @@ -229,14 +229,14 @@ define internal %struct.X* @test_nest(%struct.X* nest %a) { ; CHECK-LABEL: define {{[^@]+}}@test_nest -; CHECK-SAME: (%struct.X* nest noalias nofree readnone returned [[A:%.*]]) +; CHECK-SAME: (%struct.X* nest noalias nofree readnone returned align 536870912 [[A:%.*]]) ; CHECK-NEXT: ret %struct.X* [[A]] ; ret %struct.X* %a } define %struct.X* @complicated_args_nest() { ; CHECK-LABEL: define {{[^@]+}}@complicated_args_nest() -; CHECK-NEXT: [[CALL:%.*]] = call %struct.X* @test_nest(%struct.X* noalias nofree readnone null) +; CHECK-NEXT: [[CALL:%.*]] = call %struct.X* @test_nest(%struct.X* noalias nofree readnone align 536870912 null) ; CHECK-NEXT: ret %struct.X* [[CALL]] ; %call = call %struct.X* @test_nest(%struct.X* null)