[llvm] r369329 - [Attributor] Use structured deduction for AADereferenceable

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 19 23:08:35 PDT 2019


Author: jdoerfert
Date: Mon Aug 19 23:08:35 2019
New Revision: 369329

URL: http://llvm.org/viewvc/llvm-project?rev=369329&view=rev
Log:
[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

Modified:
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp
    llvm/trunk/test/Transforms/FunctionAttrs/align.ll
    llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll
    llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=369329&r1=369328&r2=369329&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Mon Aug 19 23:08:35 2019
@@ -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 : AADerefer
       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;
-
-  /// See AbstractAttribute::trackStatistics()
-  void trackStatistics() const override {
-    STATS_DECLTRACK_FNRET_ATTR(dereferenceable)
-  }
-};
+  ChangeStatus updateImpl(Attributor &A) override {
+    const DataLayout &DL = A.getDataLayout();
 
-// 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);
-}
+    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;
+      }
 
-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<AADereferenceable>(*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<AADereferenceable>(*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()));
+      T.takeAssumedDerefBytesMinimum(
+          std::max(int64_t(0), DerefBytes - Offset.getSExtValue()));
 
-  return 0;
-}
+      if (!Stripped &&
+          getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT) {
+        T.takeKnownDerefBytesMaximum(
+            std::max(int64_t(0), DerefBytes - Offset.getSExtValue()));
+        T.indicatePessimisticFixpoint();
+      }
 
-ChangeStatus AADereferenceableReturned::updateImpl(Attributor &A) {
-  auto BeforeState = static_cast<DerefState>(*this);
+      return T.isValidState();
+    };
 
-  bool IsGlobal = isAssumedGlobal();
+    DerefState T;
+    if (!genericValueTraversal<AADereferenceable, DerefState>(
+            A, getIRPosition(), *this, T, VisitValueCB))
+      return indicatePessimisticFixpoint();
 
-  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;
+    return clampStateAndIndicateChange(getState(), T);
   }
-  return indicatePessimisticFixpoint();
-}
-
-struct AADereferenceableArgument final : AADereferenceableImpl {
-  AADereferenceableArgument(const IRPosition &IRP)
-      : AADereferenceableImpl(IRP) {}
-
-  /// See AbstractAttribute::updateImpl(...).
-  ChangeStatus updateImpl(Attributor &A) override;
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
-    STATS_DECLTRACK_ARG_ATTR(dereferenceable)
+    STATS_DECLTRACK_FLOATING_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();
-  };
+/// Dereferenceable attribute for a return value.
+struct AADereferenceableReturned final
+    : AAReturnedFromReturnedValues<AADereferenceableImpl> {
+  AADereferenceableReturned(const IRPosition &IRP)
+      : AAReturnedFromReturnedValues<AADereferenceableImpl>(IRP) {}
 
-  if (!A.checkForAllCallSites(CallSiteCheck, *this, true))
-    return indicatePessimisticFixpoint();
+  /// See AbstractAttribute::trackStatistics()
+  void trackStatistics() const override {
+    STATS_DECLTRACK_FNRET_ATTR(dereferenceable)
+  }
+};
 
-  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
   }
 };
 
-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.

Modified: llvm/trunk/test/Transforms/FunctionAttrs/align.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/align.ll?rev=369329&r1=369328&r2=369329&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/align.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/align.ll Mon Aug 19 23:08:35 2019
@@ -92,12 +92,12 @@ define internal i8* @f1(i8* readnone %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)
 ; 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)
 ; 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
 

Modified: llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll?rev=369329&r1=369328&r2=369329&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll Mon Aug 19 23:08:35 2019
@@ -23,7 +23,7 @@ define i32* @test2(i32* dereferenceable_
 ; 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* dereferenceabl
 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

Modified: llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll?rev=369329&r1=369328&r2=369329&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll Mon Aug 19 23:08:35 2019
@@ -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




More information about the llvm-commits mailing list