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 @@ -593,8 +593,9 @@ /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { - return F, StateType>::updateImpl(A) | - G::updateImpl(A); + ChangeStatus ChangedF = F, StateType>::updateImpl(A); + ChangeStatus ChangedG = G::updateImpl(A); + return ChangedF | ChangedG; } }; @@ -1535,11 +1536,16 @@ static int64_t getKnownNonNullAndDerefBytesForUse( Attributor &A, AbstractAttribute &QueryingAA, Value &AssociatedValue, const Use *U, const Instruction *I, bool &IsNonNull, bool &TrackUse) { - // TODO: Add GEP support TrackUse = false; + const Value *UseV = U->get(); + if (!UseV->getType()->isPointerTy()) + return 0; + + Type *PtrTy = UseV->getType(); const Function *F = I->getFunction(); - bool NullPointerIsDefined = F ? F->nullPointerIsDefined() : true; + bool NullPointerIsDefined = + F ? llvm::NullPointerIsDefined(F, PtrTy->getPointerAddressSpace()) : true; const DataLayout &DL = A.getInfoCache().getDL(); if (ImmutableCallSite ICS = ImmutableCallSite(I)) { if (ICS.isBundleOperand(U)) @@ -1559,19 +1565,28 @@ int64_t Offset; if (const Value *Base = getBasePointerOfAccessPointerOperand(I, Offset, DL)) { - if (Base == &AssociatedValue) { + if (Base == &AssociatedValue && getPointerOperand(I) == UseV) { int64_t DerefBytes = - Offset + - (int64_t)DL.getTypeStoreSize( - getPointerOperand(I)->getType()->getPointerElementType()); + Offset + (int64_t)DL.getTypeStoreSize(PtrTy->getPointerElementType()); IsNonNull |= !NullPointerIsDefined; return DerefBytes; } } + if (const Value *Base = + GetPointerBaseWithConstantOffset(UseV, Offset, DL, + /*AllowNonInbounds*/ false)) { + auto &DerefAA = + A.getAAFor(QueryingAA, IRPosition::value(*Base)); + IsNonNull |= (!NullPointerIsDefined && DerefAA.isKnownNonNull()); + IsNonNull |= (!NullPointerIsDefined && (Offset != 0)); + int64_t DerefBytes = DerefAA.getKnownDereferenceableBytes(); + return std::max(int64_t(0), DerefBytes - Offset); + } return 0; } + struct AANonNullImpl : AANonNull { AANonNullImpl(const IRPosition &IRP) : AANonNull(IRP) {} @@ -2539,7 +2554,7 @@ // for overflows of the dereferenceable bytes. int64_t OffsetSExt = Offset.getSExtValue(); if (OffsetSExt < 0) - Offset = 0; + OffsetSExt = 0; T.takeAssumedDerefBytesMinimum( std::max(int64_t(0), DerefBytes - OffsetSExt)); 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 @@ -370,11 +370,11 @@ ; ; Verify the maybe-redefined function is not annotated: ; -; CHECK: Function Attrs: noinline nounwind uwtable -; CHECK: define linkonce_odr i32* @maybe_redefined_fn(i32* %r) +; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable +; ATTRIBUTOR: define linkonce_odr i32* @maybe_redefined_fn(i32* %r) ; -; CHECK: Function Attrs: noinline nounwind uwtable -; CHECK: define i32* @calls_maybe_redefined_fn(i32* returned %r) +; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable +; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn(i32* returned %r) ; ; BOTH: Function Attrs: noinline nounwind uwtable ; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn(i32* %r) @@ -808,12 +808,12 @@ %c3 = call i32* @non_exact_3(i32* %a) ; We can use the information of the weak function non_exact_3 because it was ; given to us and not derived (the alignment of the returned argument). -; CHECK: %c4 = load i32, i32* %c3, align 32 +; ATTRIBUTOR: %c4 = load i32, i32* %c3, align 32 %c4 = load i32, i32* %c3 ; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1! -; CHECK: %add1 = add i32 %c0, %c1 -; CHECK: %add2 = add i32 %add1, %c2 -; CHECK: %add3 = add i32 %add2, %c3 +; ATTRIBUTOR: %add1 = add i32 %c0, %c1 +; ATTRIBUTOR: %add2 = add i32 %add1, %c2 +; ATTRIBUTOR: %add3 = add i32 %add2, %c4 %add1 = add i32 %c0, %c1 %add2 = add i32 %add1, %c2 %add3 = add i32 %add2, %c4 @@ -827,12 +827,12 @@ } define i32* @use_const() #0 { %c = call i32* @ret_const() - ; CHECK: ret i32* bitcast (i8* @G to i32*) + ; ATTRIBUTOR: ret i32* bitcast (i8* @G to i32*) ret i32* %c } define i32* @dont_use_const() #0 { %c = musttail call i32* @ret_const() - ; CHECK: ret i32* %c + ; ATTRIBUTOR: ret i32* %c ret i32* %c } 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 @@ -1,4 +1,4 @@ -; RUN: opt -attributor -attributor-manifest-internal --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR +; RUN: opt -attributor -attributor-manifest-internal --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR declare void @deref_phi_user(i32* %a); @@ -61,7 +61,7 @@ for.cond: ; preds = %for.inc, %entry %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] %a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ] -; CHECK: call void @deref_phi_user(i32* dereferenceable(4000) %a.addr.0) +; ATTRIBUTOR: call void @deref_phi_user(i32* nonnull dereferenceable(4000) %a.addr.0) call void @deref_phi_user(i32* %a.addr.0) %tmp = load i32, i32* %a.addr.0, align 4 %cmp = icmp slt i32 %i.0, %tmp @@ -91,7 +91,7 @@ for.cond: ; preds = %for.inc, %entry %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] %a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ] -; CHECK: call void @deref_phi_user(i32* %a.addr.0) +; ATTRIBUTOR: call void @deref_phi_user(i32* nonnull %a.addr.0) call void @deref_phi_user(i32* %a.addr.0) %tmp = load i32, i32* %a.addr.0, align 4 %cmp = icmp slt i32 %i.0, %tmp 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 @@ -323,8 +323,8 @@ declare void @unknown(i8*) define void @test_callsite() { entry: -; We know that 'null' in AS 0 does not alias anything and cannot be captured -; CHECK: call void @unknown(i8* noalias nocapture null) +; 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) call void @unknown(i8* null) ret void }