diff options
-rw-r--r-- | llvm/lib/Transforms/IPO/Attributor.cpp | 213 | ||||
-rw-r--r-- | llvm/test/Transforms/FunctionAttrs/align.ll | 14 | ||||
-rw-r--r-- | llvm/test/Transforms/FunctionAttrs/dereferenceable.ll | 6 | ||||
-rw-r--r-- | llvm/test/Transforms/FunctionAttrs/noalias_returned.ll | 4 |
4 files changed, 86 insertions, 151 deletions
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 76f6405eb62..984501f06a9 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -1944,6 +1944,16 @@ struct DerefState : AbstractState { } }; +template <> +ChangeStatus clampStateAndIndicateChange<DerefState>(DerefState &S, + const DerefState &R) { + ChangeStatus CS0 = clampStateAndIndicateChange<IntegerState>( + S.DerefBytesState, R.DerefBytesState); + ChangeStatus CS1 = + clampStateAndIndicateChange<IntegerState>(S.GlobalState, R.GlobalState); + return CS0 | CS1; +} + struct AADereferenceableImpl : AADereferenceable, DerefState { AADereferenceableImpl(const IRPosition &IRP) : AADereferenceable(IRP) {} using StateType = DerefState; @@ -1994,8 +2004,6 @@ struct AADereferenceableImpl : AADereferenceable, DerefState { Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes( Ctx, getAssumedDereferenceableBytes())); } - uint64_t computeAssumedDerefenceableBytes(Attributor &A, Value &V, - bool &IsGlobal); /// See AbstractAttribute::getAsStr(). const std::string getAsStr() const override { @@ -2012,146 +2020,92 @@ private: const AANonNull *NonNullAA = nullptr; }; -struct AADereferenceableReturned final : AADereferenceableImpl { - AADereferenceableReturned(const IRPosition &IRP) +/// Dereferenceable attribute for a floating value. +struct AADereferenceableFloating : AADereferenceableImpl { + AADereferenceableFloating(const IRPosition &IRP) : AADereferenceableImpl(IRP) {} /// See AbstractAttribute::updateImpl(...). - ChangeStatus updateImpl(Attributor &A) override; + ChangeStatus updateImpl(Attributor &A) override { + const DataLayout &DL = A.getDataLayout(); - /// See AbstractAttribute::trackStatistics() - void trackStatistics() const override { - STATS_DECLTRACK_FNRET_ATTR(dereferenceable) - } -}; + auto VisitValueCB = [&](Value &V, DerefState &T, bool Stripped) -> bool { + unsigned IdxWidth = + DL.getIndexSizeInBits(V.getType()->getPointerAddressSpace()); + APInt Offset(IdxWidth, 0); + const Value *Base = + V.stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + + const auto *AA = + A.getAAFor<AADereferenceable>(*this, IRPosition::value(*Base)); + int64_t DerefBytes = 0; + if (!AA || (!Stripped && + getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT)) { + // Use IR information if we did not strip anything. + // TODO: track globally. + bool CanBeNull; + DerefBytes = Base->getPointerDereferenceableBytes(DL, CanBeNull); + T.GlobalState.indicatePessimisticFixpoint(); + } else { + const DerefState &DS = static_cast<const DerefState &>(AA->getState()); + DerefBytes = DS.DerefBytesState.getAssumed(); + T.GlobalState &= DS.GlobalState; + } -// Helper function that returns dereferenceable bytes. -static uint64_t calcDifferenceIfBaseIsNonNull(int64_t DerefBytes, - int64_t Offset, bool IsNonNull) { - if (!IsNonNull) - return 0; - return std::max((int64_t)0, DerefBytes - Offset); -} + T.takeAssumedDerefBytesMinimum( + std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); -uint64_t -AADereferenceableImpl::computeAssumedDerefenceableBytes(Attributor &A, Value &V, - bool &IsGlobal) { - // TODO: Tracking the globally flag. - IsGlobal = false; + if (!Stripped && + getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT) { + T.takeKnownDerefBytesMaximum( + std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); + T.indicatePessimisticFixpoint(); + } - // First, we try to get information about V from Attributor. - if (auto *DerefAA = - A.getAAFor<AADereferenceable>(*this, IRPosition::value(V))) { - return DerefAA->getAssumedDereferenceableBytes(); - } + return T.isValidState(); + }; - // Otherwise, we try to compute assumed bytes from base pointer. - const DataLayout &DL = A.getDataLayout(); - unsigned IdxWidth = - DL.getIndexSizeInBits(V.getType()->getPointerAddressSpace()); - APInt Offset(IdxWidth, 0); - Value *Base = V.stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + DerefState T; + if (!genericValueTraversal<AADereferenceable, DerefState>( + A, getIRPosition(), *this, T, VisitValueCB)) + return indicatePessimisticFixpoint(); - if (auto *BaseDerefAA = - A.getAAFor<AADereferenceable>(*this, IRPosition::value(*Base))) { - return calcDifferenceIfBaseIsNonNull( - BaseDerefAA->getAssumedDereferenceableBytes(), Offset.getSExtValue(), - Offset != 0 || BaseDerefAA->isAssumedNonNull()); + return clampStateAndIndicateChange(getState(), T); } - // Then, use IR information. - - if (isDereferenceablePointer(Base, Base->getType(), DL)) - return calcDifferenceIfBaseIsNonNull( - DL.getTypeStoreSize(Base->getType()->getPointerElementType()), - Offset.getSExtValue(), - !NullPointerIsDefined(getAnchorScope(), - V.getType()->getPointerAddressSpace())); - - return 0; -} - -ChangeStatus AADereferenceableReturned::updateImpl(Attributor &A) { - auto BeforeState = static_cast<DerefState>(*this); - - bool IsGlobal = isAssumedGlobal(); - - auto CheckReturnValue = [&](Value &RV) -> bool { - takeAssumedDerefBytesMinimum( - computeAssumedDerefenceableBytes(A, RV, IsGlobal)); - return isValidState(); - }; - - if (A.checkForAllReturnedValues(CheckReturnValue, *this)) { - GlobalState.intersectAssumedBits(IsGlobal); - return BeforeState == static_cast<DerefState>(*this) - ? ChangeStatus::UNCHANGED - : ChangeStatus::CHANGED; + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_FLOATING_ATTR(dereferenceable) } - return indicatePessimisticFixpoint(); -} - -struct AADereferenceableArgument final : AADereferenceableImpl { - AADereferenceableArgument(const IRPosition &IRP) - : AADereferenceableImpl(IRP) {} +}; - /// See AbstractAttribute::updateImpl(...). - ChangeStatus updateImpl(Attributor &A) override; +/// Dereferenceable attribute for a return value. +struct AADereferenceableReturned final + : AAReturnedFromReturnedValues<AADereferenceableImpl> { + AADereferenceableReturned(const IRPosition &IRP) + : AAReturnedFromReturnedValues<AADereferenceableImpl>(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { - STATS_DECLTRACK_ARG_ATTR(dereferenceable) + STATS_DECLTRACK_FNRET_ATTR(dereferenceable) } }; -ChangeStatus AADereferenceableArgument::updateImpl(Attributor &A) { - Argument &Arg = cast<Argument>(getAnchorValue()); - - auto BeforeState = static_cast<DerefState>(*this); - - unsigned ArgNo = Arg.getArgNo(); - - bool IsGlobal = isAssumedGlobal(); - - // Callback function - std::function<bool(CallSite)> CallSiteCheck = [&](CallSite CS) -> bool { - assert(CS && "Sanity check: Call site was not initialized properly!"); - - // Check that DereferenceableAA is AADereferenceableCallSiteArgument. - if (auto *DereferenceableAA = A.getAAFor<AADereferenceable>( - *this, IRPosition::callsite_argument(CS, ArgNo))) { - ImmutableCallSite ICS( - &DereferenceableAA->getIRPosition().getAnchorValue()); - if (ICS && CS.getInstruction() == ICS.getInstruction()) { - takeAssumedDerefBytesMinimum( - DereferenceableAA->getAssumedDereferenceableBytes()); - IsGlobal &= DereferenceableAA->isAssumedGlobal(); - return isValidState(); - } - } - - takeAssumedDerefBytesMinimum(computeAssumedDerefenceableBytes( - A, *CS.getArgOperand(ArgNo), IsGlobal)); - - return isValidState(); - }; - - if (!A.checkForAllCallSites(CallSiteCheck, *this, true)) - return indicatePessimisticFixpoint(); - - GlobalState.intersectAssumedBits(IsGlobal); +/// Dereferenceable attribute for an argument +struct AADereferenceableArgument final + : AAArgumentFromCallSiteArguments<AADereferenceableImpl> { + AADereferenceableArgument(const IRPosition &IRP) + : AAArgumentFromCallSiteArguments<AADereferenceableImpl>(IRP) {} - return BeforeState == static_cast<DerefState>(*this) ? ChangeStatus::UNCHANGED - : ChangeStatus::CHANGED; -} + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override{ + STATS_DECLTRACK_ARG_ATTR(dereferenceable)}; +}; /// Dereferenceable attribute for a call site argument. -struct AADereferenceableCallSiteArgument final : AADereferenceableImpl { +struct AADereferenceableCallSiteArgument final : AADereferenceableFloating { AADereferenceableCallSiteArgument(const IRPosition &IRP) - : AADereferenceableImpl(IRP) {} - - /// See AbstractAttribute::updateImpl(Attributor &A). - ChangeStatus updateImpl(Attributor &A) override; + : AADereferenceableFloating(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { @@ -2159,25 +2113,6 @@ struct AADereferenceableCallSiteArgument final : AADereferenceableImpl { } }; -ChangeStatus AADereferenceableCallSiteArgument::updateImpl(Attributor &A) { - // NOTE: Never look at the argument of the callee in this method. - // If we do this, "dereferenceable" is always deduced because of the - // assumption. - - Value &V = getAssociatedValue(); - - auto BeforeState = static_cast<DerefState>(*this); - - bool IsGlobal = isAssumedGlobal(); - - takeAssumedDerefBytesMinimum( - computeAssumedDerefenceableBytes(A, V, IsGlobal)); - GlobalState.intersectAssumedBits(IsGlobal); - - return BeforeState == static_cast<DerefState>(*this) ? ChangeStatus::UNCHANGED - : ChangeStatus::CHANGED; -} - /// Dereferenceable attribute deduction for a call site return value. using AADereferenceableCallSiteReturned = AADereferenceableReturned; @@ -2247,7 +2182,7 @@ struct AAAlignFloating : AAAlignImpl { StateType T; if (!genericValueTraversal<AAAlign, StateType>(A, getIRPosition(), *this, T, VisitValueCB)) - indicatePessimisticFixpoint(); + return indicatePessimisticFixpoint(); // TODO: If we know we visited all incoming values, thus no are assumed // dead, we can take the known information from the state T. diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll index 4e606b9fa3f..cac92ef1199 100644 --- a/llvm/test/Transforms/FunctionAttrs/align.ll +++ b/llvm/test/Transforms/FunctionAttrs/align.ll @@ -92,12 +92,12 @@ define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 { ; FIXME: Until we have "on-demand" attribute generation we do not determine the ; alignment for the return value here. ; define internal nonnull align 8 i8* @f1(i8* nonnull readnone align 8 %0) -; ATTRIBUTOR: define internal i8* @f1(i8* nonnull readnone align 8 %0) +; ATTRIBUTOR: define internal i8* @f1(i8* nonnull readnone align 8 dereferenceable(1) %0) %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 ; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* @f2(i8* nonnull align 8 @a1) +; ATTRIBUTOR: %4 = tail call i8* @f2(i8* nonnull align 8 dereferenceable(1) @a1) %4 = tail call i8* @f2(i8* nonnull @a1) br label %5 @@ -111,18 +111,18 @@ define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 { ; FIXME: Until we have "on-demand" attribute generation we do not determine the ; alignment for the return value here. ; define internal nonnull align 8 i8* @f2(i8* nonnull readnone align 8 %0) -; ATTRIBUTOR: define internal i8* @f2(i8* nonnull readnone align 8 %0) +; ATTRIBUTOR: define internal i8* @f2(i8* nonnull readnone align 8 dereferenceable(1) %0) %2 = icmp eq i8* %0, null br i1 %2, label %5, label %3 ; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 8 %0) +; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 8 dereferenceable(1) %0) %4 = tail call i8* @f1(i8* nonnull %0) br label %7 ; <label>:5: ; preds = %1 -; ATTRIBUTOR: %6 = tail call i8* @f3(i8* nonnull align 16 @a2) +; ATTRIBUTOR: %6 = tail call i8* @f3(i8* nonnull align 16 dereferenceable(1) @a2) %6 = tail call i8* @f3(i8* nonnull @a2) br label %7 @@ -136,12 +136,12 @@ define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 { ; FIXME: Until we have "on-demand" attribute generation we do not determine the ; alignment for the return value here. ; define internal nonnull align 8 i8* @f3(i8* nonnull readnone align 16 %0) -; ATTRIBUTOR: define internal i8* @f3(i8* nonnull readnone align 16 %0) +; ATTRIBUTOR: define internal i8* @f3(i8* nonnull readnone align 16 dereferenceable(1) %0) %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 ; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 16 @a2) +; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 16 dereferenceable(1) @a2) %4 = tail call i8* @f1(i8* nonnull @a2) br label %5 diff --git a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll index 3175a456305..d0da030243f 100644 --- a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll +++ b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll @@ -23,7 +23,7 @@ define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8 ; GEP inbounds define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr { ; define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull dereferenceable(8) %0) -; ATTRIBUTOR: define dereferenceable_or_null(4) i32* @test3_1(i32* nonnull dereferenceable(8) %0) +; ATTRIBUTOR: define i32* @test3_1(i32* nonnull dereferenceable(8) %0) %ret = getelementptr inbounds i32, i32* %0, i64 1 ret i32* %ret } @@ -31,14 +31,14 @@ define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr { define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr { ; FIXME: Argument should be mark dereferenceable because of GEP `inbounds`. ; define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(32) %0) -; ATTRIBUTOR: define dereferenceable_or_null(16) i32* @test3_2(i32* dereferenceable_or_null(32) %0) +; ATTRIBUTOR: define i32* @test3_2(i32* dereferenceable_or_null(32) %0) %ret = getelementptr inbounds i32, i32* %0, i64 4 ret i32* %ret } define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr { ; define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr -; ATTRIBUTOR: define dereferenceable_or_null(4) i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr +; ATTRIBUTOR: define i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr %ret1 = getelementptr inbounds i32, i32* %0, i64 1 %ret2 = getelementptr inbounds i32, i32* %1, i64 2 %ret = select i1 %2, i32* %ret1, i32* %ret2 diff --git a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll index 76fdfd2ad2a..72084c18245 100644 --- a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll +++ b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll @@ -82,7 +82,7 @@ declare i8* @baz(...) nounwind uwtable ; FIXME: Until we have "on-demand" attribute generation we do not determine the ; alignment for the return value here. ; define nonnull align 8 dereferenceable(8) i8** @getter() -; CHECK: define dereferenceable_or_null(8) i8** @getter() +; CHECK: define i8** @getter() define i8** @getter() { ret i8** @G } @@ -91,7 +91,7 @@ define i8** @getter() { ; alignment for the return value here. ; Returning global pointer. Should not be noalias. ; define nonnull align 8 dereferenceable(8) i8** @calle1() -; CHECK: define dereferenceable_or_null(8) i8** @calle1() +; CHECK: define i8** @calle1() define i8** @calle1(){ %1 = call i8** @getter() ret i8** %1 |