From 2cf3cb29ab388a6a59009b0765da59e8af3f488d Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Tue, 20 Aug 2019 06:08:35 +0000 Subject: [PATCH] [Attributor] Use structured deduction for AADereferenceable Summary: This is analogous to D66128 but for AADereferenceable. We have the logic concentrated in the floating value updateImpl and we use the combiner helper classes for arguments and return values. The regressions will go away with "on-demand" attribute creation. Improvements are already visible in the existing tests. Reviewers: uenoku, sstefan1 Subscribers: hiraditya, bollu, jfb, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66272 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369329 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/Attributor.cpp | 213 ++++++------------ test/Transforms/FunctionAttrs/align.ll | 14 +- .../FunctionAttrs/dereferenceable.ll | 6 +- .../FunctionAttrs/noalias_returned.ll | 4 +- 4 files changed, 86 insertions(+), 151 deletions(-) diff --git a/lib/Transforms/IPO/Attributor.cpp b/lib/Transforms/IPO/Attributor.cpp index 76f6405eb62..984501f06a9 100644 --- a/lib/Transforms/IPO/Attributor.cpp +++ b/lib/Transforms/IPO/Attributor.cpp @@ -1944,6 +1944,16 @@ struct DerefState : AbstractState { } }; +template <> +ChangeStatus clampStateAndIndicateChange(DerefState &S, + const DerefState &R) { + ChangeStatus CS0 = clampStateAndIndicateChange( + S.DerefBytesState, R.DerefBytesState); + ChangeStatus CS1 = + clampStateAndIndicateChange(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(*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(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(*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( + A, getIRPosition(), *this, T, VisitValueCB)) + return indicatePessimisticFixpoint(); - if (auto *BaseDerefAA = - A.getAAFor(*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(*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(*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 { + AADereferenceableReturned(const IRPosition &IRP) + : AAReturnedFromReturnedValues(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(getAnchorValue()); - - auto BeforeState = static_cast(*this); - - unsigned ArgNo = Arg.getArgNo(); - - bool IsGlobal = isAssumedGlobal(); - - // Callback function - std::function CallSiteCheck = [&](CallSite CS) -> bool { - assert(CS && "Sanity check: Call site was not initialized properly!"); - - // Check that DereferenceableAA is AADereferenceableCallSiteArgument. - if (auto *DereferenceableAA = A.getAAFor( - *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 { + AADereferenceableArgument(const IRPosition &IRP) + : AAArgumentFromCallSiteArguments(IRP) {} - return BeforeState == static_cast(*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(*this); - - bool IsGlobal = isAssumedGlobal(); - - takeAssumedDerefBytesMinimum( - computeAssumedDerefenceableBytes(A, V, IsGlobal)); - GlobalState.intersectAssumedBits(IsGlobal); - - return BeforeState == static_cast(*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(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/test/Transforms/FunctionAttrs/align.ll b/test/Transforms/FunctionAttrs/align.ll index 4e606b9fa3f..cac92ef1199 100644 --- a/test/Transforms/FunctionAttrs/align.ll +++ b/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 ;