]> granicus.if.org Git - llvm/commitdiff
[Attributor] Use structured deduction for AADereferenceable
authorJohannes Doerfert <jdoerfert@anl.gov>
Tue, 20 Aug 2019 06:08:35 +0000 (06:08 +0000)
committerJohannes Doerfert <jdoerfert@anl.gov>
Tue, 20 Aug 2019 06:08:35 +0000 (06:08 +0000)
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
test/Transforms/FunctionAttrs/align.ll
test/Transforms/FunctionAttrs/dereferenceable.ll
test/Transforms/FunctionAttrs/noalias_returned.ll

index 76f6405eb62a0e4f9ea1bbad3bc9637e2bd4f1a8..984501f06a9abf86ac5a748980c3f1fad2f3a708 100644 (file)
@@ -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.
index 4e606b9fa3fb313c4582dfbc2ea174ebdb06c035..cac92ef11994d49c961f6c0d11fc453481200450 100644 (file)
@@ -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
 
index 3175a456305db8c0893d69cf6d391af6d8b34737..d0da030243f6b34cd37b89fa744e2ff0ac7ace47 100644 (file)
@@ -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
index 76fdfd2ad2aa3a31d47ebd2e5bc24dd104616b5f..72084c182456a97ccbaab58d377d8157cc692cb4 100644 (file)
@@ -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