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 @@ -1282,7 +1282,7 @@ StateType T; if (!genericValueTraversal(A, getIRPosition(), *this, T, VisitValueCB)) - indicatePessimisticFixpoint(); + return indicatePessimisticFixpoint(); return clampStateAndIndicateChange(getState(), T); } @@ -1909,6 +1909,16 @@ } }; +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; @@ -1959,8 +1969,6 @@ 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 { @@ -1977,146 +1985,92 @@ 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 { @@ -2124,25 +2078,6 @@ } }; -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; @@ -2212,7 +2147,7 @@ StateType T; if (!genericValueTraversal(A, getIRPosition(), *this, T, VisitValueCB)) - indicatePessimisticFixpoint(); + return indicatePessimisticFixpoint(); return clampStateAndIndicateChange(getState(), T); } diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll --- a/llvm/test/Transforms/FunctionAttrs/align.ll +++ b/llvm/test/Transforms/FunctionAttrs/align.ll @@ -92,12 +92,12 @@ ; 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 ;