From cfcca1a5b12df4d05fa4d084c8d6cac37791fa5a 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 llvm-svn: 369329 --- llvm/lib/Transforms/IPO/Attributor.cpp | 225 +++++++----------- llvm/test/Transforms/FunctionAttrs/align.ll | 14 +- .../FunctionAttrs/dereferenceable.ll | 6 +- .../FunctionAttrs/noalias_returned.ll | 4 +- 4 files changed, 92 insertions(+), 157 deletions(-) diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 76f6405eb62a..984501f06a9a 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 &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,12 +2020,70 @@ 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(); + + 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; + } + + T.takeAssumedDerefBytesMinimum( + std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); + + if (!Stripped && + getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT) { + T.takeKnownDerefBytesMaximum( + std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); + T.indicatePessimisticFixpoint(); + } + + return T.isValidState(); + }; + + DerefState T; + if (!genericValueTraversal( + A, getIRPosition(), *this, T, VisitValueCB)) + return indicatePessimisticFixpoint(); + + return clampStateAndIndicateChange(getState(), T); + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_FLOATING_ATTR(dereferenceable) + } +}; + +/// Dereferenceable attribute for a return value. +struct AADereferenceableReturned final + : AAReturnedFromReturnedValues { + AADereferenceableReturned(const IRPosition &IRP) + : AAReturnedFromReturnedValues(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { @@ -2025,133 +2091,21 @@ struct AADereferenceableReturned final : AADereferenceableImpl { } }; -// 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); -} - -uint64_t -AADereferenceableImpl::computeAssumedDerefenceableBytes(Attributor &A, Value &V, - bool &IsGlobal) { - // TODO: Tracking the globally flag. - IsGlobal = false; - - // First, we try to get information about V from Attributor. - if (auto *DerefAA = - A.getAAFor(*this, IRPosition::value(V))) { - return DerefAA->getAssumedDereferenceableBytes(); - } - - // 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); - - if (auto *BaseDerefAA = - A.getAAFor(*this, IRPosition::value(*Base))) { - return calcDifferenceIfBaseIsNonNull( - BaseDerefAA->getAssumedDereferenceableBytes(), Offset.getSExtValue(), - Offset != 0 || BaseDerefAA->isAssumedNonNull()); - } - - // 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; - } - return indicatePessimisticFixpoint(); -} - -struct AADereferenceableArgument final : AADereferenceableImpl { +/// Dereferenceable attribute for an argument +struct AADereferenceableArgument final + : AAArgumentFromCallSiteArguments { AADereferenceableArgument(const IRPosition &IRP) - : AADereferenceableImpl(IRP) {} - - /// See AbstractAttribute::updateImpl(...). - ChangeStatus updateImpl(Attributor &A) override; + : AAArgumentFromCallSiteArguments(IRP) {} /// See AbstractAttribute::trackStatistics() - void trackStatistics() const override { - STATS_DECLTRACK_ARG_ATTR(dereferenceable) - } + void trackStatistics() const override{ + STATS_DECLTRACK_ARG_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); - - return BeforeState == static_cast(*this) ? ChangeStatus::UNCHANGED - : ChangeStatus::CHANGED; -} - /// 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/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll index 4e606b9fa3fb..cac92ef11994 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 ;