[llvm] r374063 - [Attributor][MustExec] Deduce dereferenceable and nonnull attribute using MustBeExecutedContextExplorer

Hideto Ueno via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 8 08:25:57 PDT 2019


Author: uenoku
Date: Tue Oct  8 08:25:56 2019
New Revision: 374063

URL: http://llvm.org/viewvc/llvm-project?rev=374063&view=rev
Log:
[Attributor][MustExec] Deduce dereferenceable and nonnull attribute using MustBeExecutedContextExplorer

Summary:
In D65186 and related patches, MustBeExecutedContextExplorer is introduced. This enables us to traverse instructions guaranteed to execute from function entry. If we can know the argument is used as `dereferenceable` or `nonnull` in these instructions, we can mark `dereferenceable` or `nonnull` in the argument definition:

1. Memory instruction (similar to D64258)
Trace memory instruction pointer operand. Currently, only inbounds GEPs are traced.
```
define i64* @f(i64* %a) {
entry:
  %add.ptr = getelementptr inbounds i64, i64* %a, i64 1
; (because of inbounds GEP we can know that %a is at least dereferenceable(16))
  store i64 1, i64* %add.ptr, align 8
  ret i64* %add.ptr ; dereferenceable 8 (because above instruction stores into it)
}
```

2. Propagation from callsite (similar to D27855)
If `deref` or `nonnull` are known in call site parameter attributes we can also say that argument also that attribute.

```
declare void @use3(i8* %x, i8* %y, i8* %z);
declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z);

define void @parent1(i8* %a, i8* %b, i8* %c) {
  call void @use3nonnull(i8* %b, i8* %c, i8* %a)
; Above instruction is always executed so we can say that at parent1(i8* nonnnull %a, i8* nonnull %b, i8* nonnull %c)
  call void @use3(i8* %c, i8* %a, i8* %b)
  ret void
}
```

Reviewers: jdoerfert, sstefan1, spatel, reames

Reviewed By: jdoerfert

Subscribers: xbolva00, hiraditya, jfb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D65402

Modified:
    llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp
    llvm/trunk/test/Transforms/FunctionAttrs/align.ll
    llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll
    llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll
    llvm/trunk/test/Transforms/FunctionAttrs/callbacks.ll
    llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll
    llvm/trunk/test/Transforms/FunctionAttrs/internal-noalias.ll
    llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll
    llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
    llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll
    llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
    llvm/trunk/test/Transforms/FunctionAttrs/readattrs.ll
    llvm/trunk/test/Transforms/InferFunctionAttrs/dereferenceable.ll

Modified: llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/Attributor.h?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Tue Oct  8 08:25:56 2019
@@ -101,6 +101,7 @@
 #include "llvm/ADT/SetVector.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/CallGraph.h"
+#include "llvm/Analysis/MustExecute.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/IR/CallSite.h"
 #include "llvm/IR/PassManager.h"
@@ -595,7 +596,7 @@ private:
 /// instance down in the abstract attributes.
 struct InformationCache {
   InformationCache(const Module &M, AnalysisGetter &AG)
-      : DL(M.getDataLayout()), AG(AG) {
+      : DL(M.getDataLayout()), Explorer(/* ExploreInterBlock */ true), AG(AG) {
 
     CallGraph *CG = AG.getAnalysis<CallGraphAnalysis>(M);
     if (!CG)
@@ -626,6 +627,11 @@ struct InformationCache {
     return FuncRWInstsMap[&F];
   }
 
+  /// Return MustBeExecutedContextExplorer
+  MustBeExecutedContextExplorer &getMustBeExecutedContextExplorer() {
+    return Explorer;
+  }
+
   /// Return TargetLibraryInfo for function \p F.
   TargetLibraryInfo *getTargetLibraryInfoForFunction(const Function &F) {
     return AG.getAnalysis<TargetLibraryAnalysis>(F);
@@ -663,6 +669,9 @@ private:
   /// The datalayout used in the module.
   const DataLayout &DL;
 
+  /// MustBeExecutedContextExplorer
+  MustBeExecutedContextExplorer Explorer;
+
   /// Getters for analysis.
   AnalysisGetter &AG;
 
@@ -1714,6 +1723,11 @@ struct AADereferenceable
     return NonNullAA && NonNullAA->isAssumedNonNull();
   }
 
+  /// Return true if we know that the underlying value is nonnull.
+  bool isKnownNonNull() const {
+    return NonNullAA && NonNullAA->isKnownNonNull();
+  }
+
   /// Return true if we assume that underlying value is
   /// dereferenceable(_or_null) globally.
   bool isAssumedGlobal() const { return GlobalState.getAssumed(); }

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Tue Oct  8 08:25:56 2019
@@ -288,6 +288,35 @@ static bool addIfNotExistent(LLVMContext
 
   llvm_unreachable("Expected enum or string attribute!");
 }
+static const Value *getPointerOperand(const Instruction *I) {
+  if (auto *LI = dyn_cast<LoadInst>(I))
+    if (!LI->isVolatile())
+      return LI->getPointerOperand();
+
+  if (auto *SI = dyn_cast<StoreInst>(I))
+    if (!SI->isVolatile())
+      return SI->getPointerOperand();
+
+  if (auto *CXI = dyn_cast<AtomicCmpXchgInst>(I))
+    if (!CXI->isVolatile())
+      return CXI->getPointerOperand();
+
+  if (auto *RMWI = dyn_cast<AtomicRMWInst>(I))
+    if (!RMWI->isVolatile())
+      return RMWI->getPointerOperand();
+
+  return nullptr;
+}
+static const Value *getBasePointerOfAccessPointerOperand(const Instruction *I,
+                                                         int64_t &BytesOffset,
+                                                         const DataLayout &DL) {
+  const Value *Ptr = getPointerOperand(I);
+  if (!Ptr)
+    return nullptr;
+
+  return GetPointerBaseWithConstantOffset(Ptr, BytesOffset, DL,
+                                          /*AllowNonInbounds*/ false);
+}
 
 ChangeStatus AbstractAttribute::update(Attributor &A) {
   ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
@@ -654,7 +683,8 @@ struct AAArgumentFromCallSiteArguments :
 };
 
 /// Helper class for generic replication: function returned -> cs returned.
-template <typename AAType, typename Base>
+template <typename AAType, typename Base,
+          typename StateType = typename AAType::StateType>
 struct AACallSiteReturnedFromReturned : public Base {
   AACallSiteReturnedFromReturned(const IRPosition &IRP) : Base(IRP) {}
 
@@ -678,6 +708,80 @@ struct AACallSiteReturnedFromReturned :
   }
 };
 
+/// Helper class for generic deduction using must-be-executed-context
+/// Base class is required to have `followUse` method.
+
+/// bool followUse(Attributor &A, const Use *U, const Instruction *I)
+/// \param U Underlying use.
+/// \param I The user of the \p U.
+/// `followUse` returns true if the value should be tracked transitively.
+
+template <typename AAType, typename Base,
+          typename StateType = typename AAType::StateType>
+struct AAFromMustBeExecutedContext : public Base {
+  AAFromMustBeExecutedContext(const IRPosition &IRP) : Base(IRP) {}
+
+  void initialize(Attributor &A) override {
+    Base::initialize(A);
+    IRPosition &IRP = this->getIRPosition();
+    Instruction *CtxI = IRP.getCtxI();
+
+    if (!CtxI)
+      return;
+
+    for (const Use &U : IRP.getAssociatedValue().uses())
+      Uses.insert(&U);
+  }
+
+  /// See AbstractAttribute::updateImpl(...).
+  ChangeStatus updateImpl(Attributor &A) override {
+    auto BeforeState = this->getState();
+    auto &S = this->getState();
+    Instruction *CtxI = this->getIRPosition().getCtxI();
+    if (!CtxI)
+      return ChangeStatus::UNCHANGED;
+
+    MustBeExecutedContextExplorer &Explorer =
+        A.getInfoCache().getMustBeExecutedContextExplorer();
+
+    SetVector<const Use *> NextUses;
+
+    for (const Use *U : Uses) {
+      if (const Instruction *UserI = dyn_cast<Instruction>(U->getUser())) {
+        auto EIt = Explorer.begin(CtxI), EEnd = Explorer.end(CtxI);
+        bool Found = EIt.count(UserI);
+        while (!Found && ++EIt != EEnd)
+          Found = EIt.getCurrentInst() == UserI;
+        if (Found && Base::followUse(A, U, UserI))
+          for (const Use &Us : UserI->uses())
+            NextUses.insert(&Us);
+      }
+    }
+    for (const Use *U : NextUses)
+      Uses.insert(U);
+
+    return BeforeState == S ? ChangeStatus::UNCHANGED : ChangeStatus::CHANGED;
+  }
+
+private:
+  /// Container for (transitive) uses of the associated value.
+  SetVector<const Use *> Uses;
+};
+
+template <typename AAType, typename Base,
+          typename StateType = typename AAType::StateType>
+using AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext =
+    AAComposeTwoGenericDeduction<AAType, Base, StateType,
+                                 AAFromMustBeExecutedContext,
+                                 AAArgumentFromCallSiteArguments>;
+
+template <typename AAType, typename Base,
+          typename StateType = typename AAType::StateType>
+using AACallSiteReturnedFromReturnedAndMustBeExecutedContext =
+    AAComposeTwoGenericDeduction<AAType, Base, StateType,
+                                 AAFromMustBeExecutedContext,
+                                 AACallSiteReturnedFromReturned>;
+
 /// -----------------------NoUnwind Function Attribute--------------------------
 
 struct AANoUnwindImpl : AANoUnwind {
@@ -1434,6 +1538,46 @@ struct AANoFreeCallSite final : AANoFree
 };
 
 /// ------------------------ NonNull Argument Attribute ------------------------
+static int64_t getKnownNonNullAndDerefBytesForUse(
+    Attributor &A, AbstractAttribute &QueryingAA, Value &AssociatedValue,
+    const Use *U, const Instruction *I, bool &IsNonNull, bool &TrackUse) {
+  // TODO: Add GEP support
+  TrackUse = false;
+
+  const Function *F = I->getFunction();
+  bool NullPointerIsDefined = F ? F->nullPointerIsDefined() : true;
+  const DataLayout &DL = A.getInfoCache().getDL();
+  if (ImmutableCallSite ICS = ImmutableCallSite(I)) {
+    if (ICS.isBundleOperand(U))
+      return 0;
+
+    if (ICS.isCallee(U)) {
+      IsNonNull |= !NullPointerIsDefined;
+      return 0;
+    }
+
+    unsigned ArgNo = ICS.getArgumentNo(U);
+    IRPosition IRP = IRPosition::callsite_argument(ICS, ArgNo);
+    auto &DerefAA = A.getAAFor<AADereferenceable>(QueryingAA, IRP);
+    IsNonNull |= DerefAA.isKnownNonNull();
+    return DerefAA.getKnownDereferenceableBytes();
+  }
+
+  int64_t Offset;
+  if (const Value *Base = getBasePointerOfAccessPointerOperand(I, Offset, DL)) {
+    if (Base == &AssociatedValue) {
+      int64_t DerefBytes =
+          Offset +
+          (int64_t)DL.getTypeStoreSize(
+              getPointerOperand(I)->getType()->getPointerElementType());
+
+      IsNonNull |= !NullPointerIsDefined;
+      return DerefBytes;
+    }
+  }
+
+  return 0;
+}
 struct AANonNullImpl : AANonNull {
   AANonNullImpl(const IRPosition &IRP) : AANonNull(IRP) {}
 
@@ -1445,6 +1589,16 @@ struct AANonNullImpl : AANonNull {
       AANonNull::initialize(A);
   }
 
+  /// See AAFromMustBeExecutedContext
+  bool followUse(Attributor &A, const Use *U, const Instruction *I) {
+    bool IsNonNull = false;
+    bool TrackUse = false;
+    getKnownNonNullAndDerefBytesForUse(A, *this, getAssociatedValue(), U, I,
+                                       IsNonNull, TrackUse);
+    takeKnownMaximum(IsNonNull);
+    return TrackUse;
+  }
+
   /// See AbstractAttribute::getAsStr().
   const std::string getAsStr() const override {
     return getAssumed() ? "nonnull" : "may-null";
@@ -1452,12 +1606,14 @@ struct AANonNullImpl : AANonNull {
 };
 
 /// NonNull attribute for a floating value.
-struct AANonNullFloating : AANonNullImpl {
-  AANonNullFloating(const IRPosition &IRP) : AANonNullImpl(IRP) {}
+struct AANonNullFloating
+    : AAFromMustBeExecutedContext<AANonNull, AANonNullImpl> {
+  using Base = AAFromMustBeExecutedContext<AANonNull, AANonNullImpl>;
+  AANonNullFloating(const IRPosition &IRP) : Base(IRP) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    AANonNullImpl::initialize(A);
+    Base::initialize(A);
 
     if (isAtFixpoint())
       return;
@@ -1475,6 +1631,10 @@ struct AANonNullFloating : AANonNullImpl
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override {
+    ChangeStatus Change = Base::updateImpl(A);
+    if (isKnownNonNull())
+      return Change;
+
     const DataLayout &DL = A.getDataLayout();
 
     auto VisitValueCB = [&](Value &V, AAAlign::StateType &T,
@@ -1518,9 +1678,12 @@ struct AANonNullReturned final
 
 /// NonNull attribute for function argument.
 struct AANonNullArgument final
-    : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
+    : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<AANonNull,
+                                                              AANonNullImpl> {
   AANonNullArgument(const IRPosition &IRP)
-      : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP) {}
+      : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<AANonNull,
+                                                                AANonNullImpl>(
+            IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nonnull) }
@@ -1535,9 +1698,12 @@ struct AANonNullCallSiteArgument final :
 
 /// NonNull attribute for a call site return position.
 struct AANonNullCallSiteReturned final
-    : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl> {
+    : AACallSiteReturnedFromReturnedAndMustBeExecutedContext<AANonNull,
+                                                             AANonNullImpl> {
   AANonNullCallSiteReturned(const IRPosition &IRP)
-      : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl>(IRP) {}
+      : AACallSiteReturnedFromReturnedAndMustBeExecutedContext<AANonNull,
+                                                               AANonNullImpl>(
+            IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(nonnull) }
@@ -2290,6 +2456,16 @@ struct AADereferenceableImpl : AADerefer
   const StateType &getState() const override { return *this; }
   /// }
 
+  /// See AAFromMustBeExecutedContext
+  bool followUse(Attributor &A, const Use *U, const Instruction *I) {
+    bool IsNonNull = false;
+    bool TrackUse = false;
+    int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
+        A, *this, getAssociatedValue(), U, I, IsNonNull, TrackUse);
+    takeKnownDerefBytesMaximum(DerefBytes);
+    return TrackUse;
+  }
+
   void getDeducedAttributes(LLVMContext &Ctx,
                             SmallVectorImpl<Attribute> &Attrs) const override {
     // TODO: Add *_globally support
@@ -2314,12 +2490,16 @@ struct AADereferenceableImpl : AADerefer
 };
 
 /// Dereferenceable attribute for a floating value.
-struct AADereferenceableFloating : AADereferenceableImpl {
-  AADereferenceableFloating(const IRPosition &IRP)
-      : AADereferenceableImpl(IRP) {}
+struct AADereferenceableFloating
+    : AAFromMustBeExecutedContext<AADereferenceable, AADereferenceableImpl> {
+  using Base =
+      AAFromMustBeExecutedContext<AADereferenceable, AADereferenceableImpl>;
+  AADereferenceableFloating(const IRPosition &IRP) : Base(IRP) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override {
+    ChangeStatus Change = Base::updateImpl(A);
+
     const DataLayout &DL = A.getDataLayout();
 
     auto VisitValueCB = [&](Value &V, DerefState &T, bool Stripped) -> bool {
@@ -2378,7 +2558,7 @@ struct AADereferenceableFloating : AADer
             A, getIRPosition(), *this, T, VisitValueCB))
       return indicatePessimisticFixpoint();
 
-    return clampStateAndIndicateChange(getState(), T);
+    return Change | clampStateAndIndicateChange(getState(), T);
   }
 
   /// See AbstractAttribute::trackStatistics()
@@ -2403,12 +2583,11 @@ struct AADereferenceableReturned final
 
 /// Dereferenceable attribute for an argument
 struct AADereferenceableArgument final
-    : AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl,
-                                      DerefState> {
-  AADereferenceableArgument(const IRPosition &IRP)
-      : AAArgumentFromCallSiteArguments<AADereferenceable,
-                                        AADereferenceableImpl, DerefState>(
-            IRP) {}
+    : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<
+          AADereferenceable, AADereferenceableImpl, DerefState> {
+  using Base = AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<
+      AADereferenceable, AADereferenceableImpl, DerefState>;
+  AADereferenceableArgument(const IRPosition &IRP) : Base(IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
@@ -2428,13 +2607,16 @@ struct AADereferenceableCallSiteArgument
 };
 
 /// Dereferenceable attribute deduction for a call site return value.
-struct AADereferenceableCallSiteReturned final : AADereferenceableImpl {
-  AADereferenceableCallSiteReturned(const IRPosition &IRP)
-      : AADereferenceableImpl(IRP) {}
+struct AADereferenceableCallSiteReturned final
+    : AACallSiteReturnedFromReturnedAndMustBeExecutedContext<
+          AADereferenceable, AADereferenceableImpl> {
+  using Base = AACallSiteReturnedFromReturnedAndMustBeExecutedContext<
+      AADereferenceable, AADereferenceableImpl>;
+  AADereferenceableCallSiteReturned(const IRPosition &IRP) : Base(IRP) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    AADereferenceableImpl::initialize(A);
+    Base::initialize(A);
     Function *F = getAssociatedFunction();
     if (!F)
       indicatePessimisticFixpoint();
@@ -2446,11 +2628,14 @@ struct AADereferenceableCallSiteReturned
     //       call site specific liveness information and then it makes
     //       sense to specialize attributes for call sites arguments instead of
     //       redirecting requests to the callee argument.
+
+    ChangeStatus Change = Base::updateImpl(A);
     Function *F = getAssociatedFunction();
     const IRPosition &FnPos = IRPosition::returned(*F);
     auto &FnAA = A.getAAFor<AADereferenceable>(*this, FnPos);
-    return clampStateAndIndicateChange(
-        getState(), static_cast<const DerefState &>(FnAA.getState()));
+    return Change |
+           clampStateAndIndicateChange(
+               getState(), static_cast<const DerefState &>(FnAA.getState()));
   }
 
   /// See AbstractAttribute::trackStatistics()

Modified: llvm/trunk/test/Transforms/FunctionAttrs/align.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/align.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/align.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/align.ll Tue Oct  8 08:25:56 2019
@@ -175,7 +175,7 @@ define void @test9_traversal(i1 %c, i32*
 
 ; FIXME: This will work with an upcoming patch (D66618 or similar)
 ;             define align 32 i32* @test10a(i32* align 32 "no-capture-maybe-returned" %p)
-; ATTRIBUTOR: define i32* @test10a(i32* align 32 "no-capture-maybe-returned" %p)
+; ATTRIBUTOR: define i32* @test10a(i32* nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p)
 define i32* @test10a(i32* align 32 %p) {
 ; ATTRIBUTOR: %l = load i32, i32* %p, align 32
   %l = load i32, i32* %p
@@ -203,7 +203,7 @@ e:
 
 ; FIXME: This will work with an upcoming patch (D66618 or similar)
 ;             define align 32 i32* @test10b(i32* align 32 "no-capture-maybe-returned" %p)
-; ATTRIBUTOR: define i32* @test10b(i32* align 32 "no-capture-maybe-returned" %p)
+; ATTRIBUTOR: define i32* @test10b(i32* nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p)
 define i32* @test10b(i32* align 32 %p) {
 ; ATTRIBUTOR: %l = load i32, i32* %p, align 32
   %l = load i32, i32* %p

Modified: llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll Tue Oct  8 08:25:56 2019
@@ -244,7 +244,8 @@ declare i32 @printf(i8* nocapture, ...)
 ; }
 ;
 ; There should *not* be a no-capture attribute on %a
-; CHECK: define i64* @not_captured_but_returned_0(i64* returned writeonly "no-capture-maybe-returned" %a)
+; CHECK: define nonnull dereferenceable(8) i64* @not_captured_but_returned_0(i64* nonnull returned writeonly dereferenceable(8) "no-capture-maybe-returned" %a)
+
 define i64* @not_captured_but_returned_0(i64* %a) #0 {
 entry:
   store i64 0, i64* %a, align 8
@@ -354,6 +355,7 @@ entry:
 ;
 ; CHECK:     define i32* @ret_arg_or_unknown(i32* readnone %b)
 ; CHECK:     define i32* @ret_arg_or_unknown_through_phi(i32* readnone %b)
+
 declare i32* @unknown()
 
 define i32* @ret_arg_or_unknown(i32* %b) #0 {

Modified: llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll Tue Oct  8 08:25:56 2019
@@ -254,7 +254,7 @@ return:
 ;
 ; FNATTR:  define i32* @rt0(i32* readonly %a)
 ; BOTH: Function Attrs: nofree noinline noreturn nosync nounwind readonly uwtable
-; BOTH-NEXT:    define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture readonly %a)
+; BOTH-NEXT:    define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture nonnull readonly dereferenceable(4) %a)
 define i32* @rt0(i32* %a) #0 {
 entry:
   %v = load i32, i32* %a, align 4
@@ -272,7 +272,7 @@ entry:
 ;
 ; FNATTR:  define noalias i32* @rt1(i32* nocapture readonly %a)
 ; BOTH: Function Attrs: nofree noinline noreturn nosync nounwind readonly uwtable
-; BOTH-NEXT:    define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture readonly %a)
+; BOTH-NEXT:    define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture nonnull readonly dereferenceable(4) %a)
 define i32* @rt1(i32* %a) #0 {
 entry:
   %v = load i32, i32* %a, align 4

Modified: llvm/trunk/test/Transforms/FunctionAttrs/callbacks.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/callbacks.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/callbacks.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/callbacks.ll Tue Oct  8 08:25:56 2019
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
+; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
 ; ModuleID = 'callback_simple.c'
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 
@@ -14,7 +14,7 @@ target datalayout = "e-m:e-p270:32:32-p2
 ; FIXME: The callee -> call site direction is not working yet.
 
 define void @t0_caller(i32* %a) {
-; CHECK:       @t0_caller(i32* [[A:%.*]])
+; CHECK-LABEL: @t0_caller(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 32
 ; CHECK-NEXT:    [[C:%.*]] = alloca i32*, align 64
@@ -39,7 +39,7 @@ entry:
 ; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
 ; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
 define internal void @t0_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) {
-; CHECK:       @t0_callback_callee(i32* nocapture writeonly [[IS_NOT_NULL:%.*]], i32* nocapture readonly [[PTR:%.*]], i32* [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
+; CHECK-LABEL: @t0_callback_callee(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[PTR_VAL:%.*]] = load i32, i32* [[PTR:%.*]], align 8
 ; CHECK-NEXT:    store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL:%.*]]

Modified: llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/dereferenceable.ll Tue Oct  8 08:25:56 2019
@@ -1,4 +1,4 @@
-; RUN: opt -attributor -attributor-manifest-internal --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
+; RUN: opt -attributor -attributor-manifest-internal --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
 
 
 declare void @deref_phi_user(i32* %a);
@@ -111,3 +111,94 @@ for.inc:
 for.end:                                          ; preds = %for.cond.cleanup
   ret void
 }
+
+; TEST 7
+; share known infomation in must-be-executed-context
+declare i32* @unkown_ptr() willreturn nounwind
+declare i32 @unkown_f(i32*) willreturn nounwind
+define i32* @f7_0(i32* %ptr) {
+; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @f7_0(i32* nonnull returned dereferenceable(8) %ptr)
+  %T = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
+  ret i32* %ptr
+}	
+
+; ATTRIBUTOR: define void @f7_1(i32* nonnull dereferenceable(4) %ptr, i1 %c) 
+define void @f7_1(i32* %ptr, i1 %c) {
+
+; ATTRIBUTOR:   %A = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) 
+  %A = tail call i32 @unkown_f(i32* %ptr)
+
+  %ptr.0 = load i32, i32* %ptr
+  ; deref 4 hold
+
+; FIXME: this should be %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) 
+; ATTRIBUTOR:   %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) 
+  %B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
+
+  br i1%c, label %if.true, label %if.false
+if.true:
+; ATTRIBUTOR:   %C = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
+  %C = tail call i32 @unkown_f(i32* %ptr)
+
+; ATTRIBUTOR:   %D = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
+  %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
+
+; FIXME: This should be tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
+;        Making must-be-executed-context backward exploration will fix this.
+; ATTRIBUTOR:   %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) 
+  %E = tail call i32 @unkown_f(i32* %ptr)
+
+  ret void
+
+if.false:
+  ret void
+}
+
+; ATTRIBUTOR: define void @f7_2(i1 %c) 
+define void @f7_2(i1 %c) {
+
+  %ptr =  tail call i32* @unkown_ptr()
+
+; ATTRIBUTOR:   %A = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) 
+  %A = tail call i32 @unkown_f(i32* %ptr)
+
+  %arg_a.0 = load i32, i32* %ptr
+  ; deref 4 hold
+
+; ATTRIBUTOR:   %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr)
+  %B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
+
+  br i1%c, label %if.true, label %if.false
+if.true:
+
+; ATTRIBUTOR:   %C = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
+  %C = tail call i32 @unkown_f(i32* %ptr)
+
+; ATTRIBUTOR:   %D = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
+  %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
+
+  %E = tail call i32 @unkown_f(i32* %ptr)
+; FIXME: This should be @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
+;        Making must-be-executed-context backward exploration will fix this.
+; ATTRIBUTOR:   %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr)
+
+  ret void
+
+if.false:
+  ret void
+}
+
+define i32* @f7_3() {
+; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @f7_3()
+  %ptr = tail call i32* @unkown_ptr()
+  store i32 10, i32* %ptr, align 16
+  ret i32* %ptr
+}
+
+define i32* @test_for_minus_index(i32* %p) {
+; FIXME: This should be define nonnull dereferenceable(8) i32* @test_for_minus_index(i32* nonnull %p)
+; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @test_for_minus_index(i32* writeonly "no-capture-maybe-returned" %p)
+  %q = getelementptr inbounds i32, i32* %p, i32 -2
+  store i32 1, i32* %q
+  ret i32* %q
+}

Modified: llvm/trunk/test/Transforms/FunctionAttrs/internal-noalias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/internal-noalias.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/internal-noalias.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/internal-noalias.ll Tue Oct  8 08:25:56 2019
@@ -8,7 +8,7 @@ entry:
   ret i32 %add
 }
 
-; CHECK: define private i32 @noalias_args(i32* nocapture readonly %A, i32* noalias nocapture readonly %B)
+; CHECK: define private i32 @noalias_args(i32* nocapture nonnull readonly dereferenceable(4) %A, i32* noalias nocapture nonnull readonly dereferenceable(4) %B)
 
 define private i32 @noalias_args(i32* %A, i32* %B) #0 {
 entry:
@@ -23,7 +23,8 @@ entry:
 
 ; FIXME: Should be something like this.
 ; define internal i32 @noalias_args_argmem(i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %B)
-; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture readonly %A, i32* nocapture readonly %B)
+; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nonnull readonly dereferenceable(4) %A, i32* nocapture nonnull readonly dereferenceable(4) %B)
+
 ;
 define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 {
 entry:

Modified: llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll Tue Oct  8 08:25:56 2019
@@ -40,7 +40,7 @@ define i32 @volatile_load(i32*) norecurs
 }
 
 ; CHECK: Function Attrs: nofree norecurse nosync nounwind readonly uwtable willreturn
-; CHECK-NEXT: define internal i32 @internal_load(i32* nocapture nonnull readonly %0)
+; CHECK-NEXT: define internal i32 @internal_load(i32* nocapture nonnull readonly dereferenceable(4) %0)
 define internal i32 @internal_load(i32*) norecurse nounwind uwtable {
   %2 = load i32, i32* %0, align 4
   ret i32 %2

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=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll Tue Oct  8 08:25:56 2019
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
+; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
 
 ; TEST 1 - negative.
 

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll Tue Oct  8 08:25:56 2019
@@ -120,7 +120,9 @@ define void @nc2(i32* %p, i32* %q) {
 	ret void
 }
 
-; EITHER: define void @nc3(void ()* nocapture %p)
+
+; FNATTR: define void @nc3(void ()* nocapture %p)
+; ATTRIBUTOR: define void @nc3(void ()* nocapture nonnull %p)
 define void @nc3(void ()* %p) {
 	call void %p()
 	ret void
@@ -133,7 +135,8 @@ define void @nc4(i8* %p) {
 	ret void
 }
 
-; EITHER: define void @nc5(void (i8*)* nocapture %f, i8* nocapture %p)
+; FNATTR: define void @nc5(void (i8*)* nocapture %f, i8* nocapture %p)
+; ATTRIBUTOR: define void @nc5(void (i8*)* nocapture nonnull %f, i8* nocapture %p)
 define void @nc5(void (i8*)* %f, i8* %p) {
 	call void %f(i8* %p) readonly nounwind
 	call void %f(i8* nocapture %p)
@@ -213,19 +216,22 @@ define void @test6_2(i8* %x6_2, i8* %y6_
   ret void
 }
 
-; EITHER: define void @test_cmpxchg(i32* nocapture %p)
+; FNATTR: define void @test_cmpxchg(i32* nocapture %p)
+; ATTRIBUTOR: define void @test_cmpxchg(i32* nocapture nonnull dereferenceable(4) %p)
 define void @test_cmpxchg(i32* %p) {
   cmpxchg i32* %p, i32 0, i32 1 acquire monotonic
   ret void
 }
 
-; EITHER: define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q)
+; FNATTR: define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q)
+; ATTRIBUTOR: define void @test_cmpxchg_ptr(i32** nocapture nonnull dereferenceable(8) %p, i32* %q)
 define void @test_cmpxchg_ptr(i32** %p, i32* %q) {
   cmpxchg i32** %p, i32* null, i32* %q acquire monotonic
   ret void
 }
 
-; EITHER: define void @test_atomicrmw(i32* nocapture %p)
+; FNATTR: define void @test_atomicrmw(i32* nocapture %p)
+; ATTRIBUTOR: define void @test_atomicrmw(i32* nocapture nonnull dereferenceable(4) %p)
 define void @test_atomicrmw(i32* %p) {
   atomicrmw add i32* %p, i32 1 seq_cst
   ret void

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll Tue Oct  8 08:25:56 2019
@@ -236,6 +236,104 @@ define void @f15(i8* %arg) {
   ret void
 }
 
+declare void @fun0() #1
+declare void @fun1(i8*) #1
+declare void @fun2(i8*, i8*) #1
+declare void @fun3(i8*, i8*, i8*) #1
+; TEST 16 simple path test
+; if(..)
+;   fun2(nonnull %a, nonnull %b)
+; else
+;   fun2(nonnull %a, %b)
+; We can say that %a is nonnull but %b is not.
+define void @f16(i8* %a, i8 * %b, i8 %c) {
+; FIXME: missing nonnull on %a
+; ATTRIBUTOR: define void @f16(i8* %a, i8* %b, i8 %c)
+  %cmp = icmp eq i8 %c, 0
+  br i1 %cmp, label %if.then, label %if.else
+if.then:
+  tail call void @fun2(i8* nonnull %a, i8* nonnull %b)
+  ret void
+if.else:
+  tail call void @fun2(i8* nonnull %a, i8* %b)
+  ret void
+}
+; TEST 17 explore child BB test
+; if(..)
+;    ... (willreturn & nounwind)
+; else
+;    ... (willreturn & nounwind)
+; fun1(nonnull %a)
+; We can say that %a is nonnull
+define void @f17(i8* %a, i8 %c) {
+; FIXME: missing nonnull on %a
+; ATTRIBUTOR: define void @f17(i8* %a, i8 %c)
+  %cmp = icmp eq i8 %c, 0
+  br i1 %cmp, label %if.then, label %if.else
+if.then:
+  tail call void @fun0()
+  br label %cont
+if.else:
+  tail call void @fun0()
+  br label %cont
+cont:
+  tail call void @fun1(i8* nonnull %a)
+  ret void
+}
+; TEST 18 More complex test
+; if(..)
+;    ... (willreturn & nounwind)
+; else
+;    ... (willreturn & nounwind)
+; if(..)
+;    ... (willreturn & nounwind)
+; else
+;    ... (willreturn & nounwind)
+; fun1(nonnull %a)
+
+define void @f18(i8* %a, i8* %b, i8 %c) {
+; FIXME: missing nonnull on %a
+; ATTRIBUTOR: define void @f18(i8* %a, i8* %b, i8 %c)
+  %cmp1 = icmp eq i8 %c, 0
+  br i1 %cmp1, label %if.then, label %if.else
+if.then:
+  tail call void @fun0()
+  br label %cont
+if.else:
+  tail call void @fun0()
+  br label %cont
+cont:
+  %cmp2 = icmp eq i8 %c, 1
+  br i1 %cmp2, label %cont.then, label %cont.else
+cont.then:
+  tail call void @fun1(i8* nonnull %b)
+  br label %cont2
+cont.else:
+  tail call void @fun0()
+  br label %cont2
+cont2:
+  tail call void @fun1(i8* nonnull %a)
+  ret void
+}
+
+; TEST 19: Loop
+
+define void @f19(i8* %a, i8* %b, i8 %c) {
+; FIXME: missing nonnull on %b
+; ATTRIBUTOR: define void @f19(i8* %a, i8* %b, i8 %c)
+  br label %loop.header
+loop.header:
+  %cmp2 = icmp eq i8 %c, 0
+  br i1 %cmp2, label %loop.body, label %loop.exit
+loop.body:
+  tail call void @fun1(i8* nonnull %b)
+  tail call void @fun1(i8* nonnull %a)
+  br label %loop.header
+loop.exit:
+  tail call void @fun1(i8* nonnull %b)
+  ret void
+}
+
 ; Test propagation of nonnull callsite args back to caller.
 
 declare void @use1(i8* %x)
@@ -268,14 +366,9 @@ define void @parent2(i8* %a, i8* %b, i8*
 ; FNATTR-NEXT:    call void @use3nonnull(i8* %b, i8* %c, i8* %a)
 ; FNATTR-NEXT:    call void @use3(i8* %c, i8* %a, i8* %b)
 
-; FIXME: missing "nonnull", it should be
-; @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c)
-;     call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a)
-;     call void @use3(i8* nonnull %c, i8* nonnull %a, i8* nonnull %b)
-
-; ATTRIBUTOR-LABEL: @parent2(i8* %a, i8* %b, i8* %c)
+; ATTRIBUTOR-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c)
 ; ATTRIBUTOR-NEXT:    call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a)
-; ATTRIBUTOR-NEXT:    call void @use3(i8* %c, i8* %a, i8* %b)
+; ATTRIBUTOR-NEXT:    call void @use3(i8* nonnull %c, i8* nonnull %a, i8* nonnull %b)
 
 ; BOTH-NEXT:    ret void
   call void @use3nonnull(i8* %b, i8* %c, i8* %a)
@@ -290,13 +383,9 @@ define void @parent3(i8* %a, i8* %b, i8*
 ; FNATTR-NEXT:    call void @use1nonnull(i8* %a)
 ; FNATTR-NEXT:    call void @use3(i8* %c, i8* %b, i8* %a)
 
-; FIXME: missing "nonnull", it should be,
-; @parent3(i8* nonnull %a, i8* %b, i8* %c)
-;    call void @use1nonnull(i8* nonnull %a)
-;    call void @use3(i8* %c, i8* %b, i8* nonnull %a)
-; ATTRIBUTOR-LABEL: @parent3(i8* %a, i8* %b, i8* %c)
+; ATTRIBUTOR-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c)
 ; ATTRIBUTOR-NEXT:    call void @use1nonnull(i8* nonnull %a)
-; ATTRIBUTOR-NEXT:    call void @use3(i8* %c, i8* %b, i8* %a)
+; ATTRIBUTOR-NEXT:    call void @use3(i8* %c, i8* %b, i8* nonnull %a)
 
 ; BOTH-NEXT:  ret void
 
@@ -313,16 +402,10 @@ define void @parent4(i8* %a, i8* %b, i8*
 ; CHECK-NEXT:    call void @use2(i8* %a, i8* %c)
 ; CHECK-NEXT:    call void @use1(i8* %b)
 
-; FIXME : missing "nonnull", it should be
-; @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c)
-;   call void @use2nonnull(i8* nonnull %c, i8* nonull %b)
-;   call void @use2(i8* %a, i8* nonnull %c)
-;   call void @use1(i8* nonnull %b)
-
-; ATTRIBUTOR-LABEL: @parent4(i8* %a, i8* %b, i8* %c)
+; ATTRIBUTOR-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c)
 ; ATTRIBUTOR-NEXT:    call void @use2nonnull(i8* nonnull %c, i8* nonnull %b)
-; ATTRIBUTOR-NEXT:    call void @use2(i8* %a, i8* %c)
-; ATTRIBUTOR-NEXT:    call void @use1(i8* %b)
+; ATTRIBUTOR-NEXT:    call void @use2(i8* %a, i8* nonnull %c)
+; ATTRIBUTOR-NEXT:    call void @use1(i8* nonnull %b)
 
 ; BOTH: ret void
 
@@ -359,8 +442,7 @@ f:
 
 define i8 @parent6(i8* %a, i8* %b) {
 ; FNATTR-LABEL: @parent6(i8* nonnull %a, i8* %b)
-; FIXME: missing "nonnull"
-; ATTRIBUTOR-LABEL: @parent6(i8* %a, i8* %b)
+; ATTRIBUTOR-LABEL: @parent6(i8* nonnull %a, i8* %b)
 ; BOTH-NEXT:    [[C:%.*]] = load volatile i8, i8* %b
 ; FNATTR-NEXT:    call void @use1nonnull(i8* %a)
 ; ATTRIBUTOR-NEXT:    call void @use1nonnull(i8* nonnull %a)
@@ -378,14 +460,9 @@ define i8 @parent7(i8* %a) {
 ; FNATTR-NEXT:    [[RET:%.*]] = call i8 @use1safecall(i8* %a)
 ; FNATTR-NEXT:    call void @use1nonnull(i8* %a)
 
-; FIXME : missing "nonnull", it should be
-; @parent7(i8* nonnull %a)
-;   [[RET:%.*]] = call i8 @use1safecall(i8* nonnull %a)
-;   call void @use1nonnull(i8* nonnull %a)
-;   ret i8 [[RET]]
 
-; ATTRIBUTOR-LABEL: @parent7(i8* %a)
-; ATTRIBUTOR-NEXT:    [[RET:%.*]] = call i8 @use1safecall(i8* %a)
+; ATTRIBUTOR-LABEL: @parent7(i8* nonnull %a)
+; ATTRIBUTOR-NEXT:    [[RET:%.*]] = call i8 @use1safecall(i8* nonnull %a)
 ; ATTRIBUTOR-NEXT:    call void @use1nonnull(i8* nonnull %a)
 
 ; BOTH-NEXT: ret i8 [[RET]]
@@ -400,9 +477,7 @@ define i8 @parent7(i8* %a) {
 declare i32 @esfp(...)
 
 define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){
-; FNATTR-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b)
-; FIXME : missing "nonnull", it should be @parent8(i8* nonnull %a, i8* %bogus1, i8* nonnull %b)
-; ATTRIBUTOR-LABEL: @parent8(i8* %a, i8* nocapture readnone %bogus1, i8* %b)
+; BOTH-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b) 
 ; BOTH-NEXT:  entry:
 ; FNATTR-NEXT:    invoke void @use2nonnull(i8* %a, i8* %b)
 ; ATTRIBUTOR-NEXT:    invoke void @use2nonnull(i8* nonnull %a, i8* nonnull %b)
@@ -470,4 +545,6 @@ define weak_odr void @weak_caller(i32* n
   ret void
 }
 
+
 attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #1 = { nounwind willreturn}

Modified: llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll Tue Oct  8 08:25:56 2019
@@ -130,8 +130,15 @@ define linkonce_odr i32 @leaf_redefinabl
 
 ; Call through a function pointer
 ; ATTRIBUTOR-NOT: Function Attrs
-; ATTRIBUTOR: define i32 @eval_func(i32 (i32)* nocapture %0, i32 %1)
-define i32 @eval_func(i32 (i32)* , i32) local_unnamed_addr {
+; ATTRIBUTOR: define i32 @eval_func1(i32 (i32)* nocapture nonnull %0, i32 %1)
+define i32 @eval_func1(i32 (i32)* , i32) local_unnamed_addr {
+  %3 = tail call i32 %0(i32 %1) #2
+  ret i32 %3
+}
+
+; ATTRIBUTOR-NOT: Function Attrs
+; ATTRIBUTOR: define i32 @eval_func2(i32 (i32)* nocapture %0, i32 %1)
+define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr "null-pointer-is-valid"="true"{
   %3 = tail call i32 %0(i32 %1) #2
   ret i32 %3
 }

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll Tue Oct  8 08:25:56 2019
@@ -45,7 +45,7 @@ entry:
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define i32 @load_monotonic(i32* nocapture readonly %0)
 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
-; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture readonly %0)
+; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture nonnull readonly dereferenceable(4) %0)
 define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable {
   %2 = load atomic i32, i32* %0 monotonic, align 4
   ret i32 %2
@@ -61,7 +61,7 @@ define i32 @load_monotonic(i32* nocaptur
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define void @store_monotonic(i32* nocapture %0)
 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
-; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture writeonly %0)
+; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture nonnull writeonly dereferenceable(4) %0) 
 define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
   store atomic i32 10, i32* %0 monotonic, align 4
   ret void
@@ -78,7 +78,7 @@ define void @store_monotonic(i32* nocapt
 ; FNATTR-NEXT: define i32 @load_acquire(i32* nocapture readonly %0)
 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
-; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture readonly %0)
+; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture nonnull readonly dereferenceable(4) %0)
 define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable {
   %2 = load atomic i32, i32* %0 acquire, align 4
   ret i32 %2
@@ -224,7 +224,8 @@ define void @scc2(i32* %0) noinline noun
 ; FNATTR: Function Attrs: nofree norecurse nounwind
 ; FNATTR-NEXT: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
 ; ATTRIBUTOR-NOT: nosync
-; ATTRIBUTOR: define void @foo1(i32* nocapture writeonly %0, %"struct.std::atomic"* nocapture writeonly %1)
+; ATTRIBUTOR: define void @foo1(i32* nocapture nonnull writeonly dereferenceable(4) %0, %"struct.std::atomic"* nocapture writeonly %1)
+
 define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
   store i32 100, i32* %0, align 4
   fence release
@@ -255,8 +256,9 @@ define void @bar(i32* %0, %"struct.std::
 ; TEST 13 - Fence syncscope("singlethread") seq_cst
 ; FNATTR: Function Attrs: nofree norecurse nounwind
 ; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
-; ATTRIBUTOR: Function Attrs: nofree nosync
-; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture writeonly %0, %"struct.std::atomic"* nocapture writeonly %1)
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind willreturn
+; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture nonnull writeonly dereferenceable(4) %0, %"struct.std::atomic"* nocapture writeonly %1)
+
 define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
   store i32 100, i32* %0, align 4
   fence syncscope("singlethread") release
@@ -267,7 +269,7 @@ define void @foo1_singlethread(i32* %0,
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind
 ; FNATTR-NEXT: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
-; ATTRIBUTOR: Function Attrs: nofree nosync
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
 ; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
 define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) {
   %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0

Modified: llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll Tue Oct  8 08:25:56 2019
@@ -70,7 +70,7 @@ return:
 }
 
 ; CHECK: Function Attrs: nofree nosync nounwind
-; CHECK-NEXT: define internal i32* @internal_ret1_rrw(i32* %r0, i32* returned %r1, i32* %w0)
+; CHECK-NEXT: define internal i32* @internal_ret1_rrw(i32* nonnull dereferenceable(4) %r0, i32* returned %r1, i32* %w0)
 define internal i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) {
 entry:
   %0 = load i32, i32* %r0, align 4
@@ -121,7 +121,7 @@ return:
 }
 
 ; CHECK: Function Attrs: nofree nosync nounwind
-; CHECK-NEXT: define internal i32* @internal_ret1_rw(i32* %r0, i32* returned %w0)
+; CHECK-NEXT: define internal i32* @internal_ret1_rw(i32* nonnull dereferenceable(4) %r0, i32* returned %w0)
 define internal i32* @internal_ret1_rw(i32* %r0, i32* %w0) {
 entry:
   %0 = load i32, i32* %r0, align 4

Modified: llvm/trunk/test/Transforms/FunctionAttrs/readattrs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/readattrs.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/readattrs.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/readattrs.ll Tue Oct  8 08:25:56 2019
@@ -39,7 +39,7 @@ define void @test4_2(i8* %p) {
 }
 
 ; FNATTR: define void @test5(i8** nocapture %p, i8* %q)
-; ATTRIBUTOR: define void @test5(i8** nocapture writeonly %p, i8* %q)
+; ATTRIBUTOR: define void @test5(i8** nocapture nonnull writeonly dereferenceable(8) %p, i8* %q)
 ; Missed optz'n: we could make %q readnone, but don't break test6!
 define void @test5(i8** %p, i8* %q) {
   store i8* %q, i8** %p
@@ -48,7 +48,7 @@ define void @test5(i8** %p, i8* %q) {
 
 declare void @test6_1()
 ; FNATTR: define void @test6_2(i8** nocapture %p, i8* %q)
-; ATTRIBUTOR: define void @test6_2(i8** nocapture writeonly %p, i8* %q)
+; ATTRIBUTOR: define void @test6_2(i8** nocapture nonnull writeonly dereferenceable(8) %p, i8* %q)
 ; This is not a missed optz'n.
 define void @test6_2(i8** %p, i8* %q) {
   store i8* %q, i8** %p

Modified: llvm/trunk/test/Transforms/InferFunctionAttrs/dereferenceable.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InferFunctionAttrs/dereferenceable.ll?rev=374063&r1=374062&r2=374063&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InferFunctionAttrs/dereferenceable.ll (original)
+++ llvm/trunk/test/Transforms/InferFunctionAttrs/dereferenceable.ll Tue Oct  8 08:25:56 2019
@@ -1,10 +1,17 @@
 ; RUN: opt < %s -inferattrs -S | FileCheck %s
+; RUN: opt < %s -attributor --attributor-disable=false -S | FileCheck %s --check-prefix=ATTRIBUTOR
+
+
 
 ; Determine dereference-ability before unused loads get deleted:
 ; https://bugs.llvm.org/show_bug.cgi?id=21780
 
 define <4 x double> @PR21780(double* %ptr) {
 ; CHECK-LABEL: @PR21780(double* %ptr)
+; FIXME: this should be @PR21780(double* nonnull dereferenceable(32) %ptr) 
+;        trakcing use of GEP in Attributor would fix this problem.
+; ATTRIBUTOR-LABEL: @PR21780(double* nocapture nonnull readonly dereferenceable(8) %ptr)
+
   ; GEP of index 0 is simplified away.
   %arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1
   %arrayidx2 = getelementptr inbounds double, double* %ptr, i64 2
@@ -23,6 +30,43 @@ define <4 x double> @PR21780(double* %pt
   ret <4 x double> %shuffle
 }
 
+
+define double @PR21780_only_access3_with_inbounds(double* %ptr) {
+; CHECK-LABEL: @PR21780_only_access3_with_inbounds(double* %ptr)
+; FIXME: this should be @PR21780_only_access3_with_inbounds(double* nonnull dereferenceable(32) %ptr)
+;        trakcing use of GEP in Attributor would fix this problem.
+; ATTRIBUTOR-LABEL: @PR21780_only_access3_with_inbounds(double* nocapture readonly %ptr) 
+
+  %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3
+  %t3 = load double, double* %arrayidx3, align 8
+  ret double %t3
+}
+
+define double @PR21780_only_access3_without_inbounds(double* %ptr) {
+; CHECK-LABEL: @PR21780_only_access3_without_inbounds(double* %ptr)
+; ATTRIBUTOR-LABEL: @PR21780_only_access3_without_inbounds(double* nocapture readonly %ptr)
+  %arrayidx3 = getelementptr double, double* %ptr, i64 3
+  %t3 = load double, double* %arrayidx3, align 8
+  ret double %t3
+}
+
+define double @PR21780_without_inbounds(double* %ptr) {
+; CHECK-LABEL: @PR21780_without_inbounds(double* %ptr)
+; FIXME: this should be @PR21780_without_inbounds(double* nonnull dereferenceable(32) %ptr)
+; ATTRIBUTOR-LABEL: @PR21780_without_inbounds(double* nocapture nonnull readonly dereferenceable(8) %ptr)
+
+  %arrayidx1 = getelementptr double, double* %ptr, i64 1
+  %arrayidx2 = getelementptr double, double* %ptr, i64 2
+  %arrayidx3 = getelementptr double, double* %ptr, i64 3
+
+  %t0 = load double, double* %ptr, align 8
+  %t1 = load double, double* %arrayidx1, align 8
+  %t2 = load double, double* %arrayidx2, align 8
+  %t3 = load double, double* %arrayidx3, align 8
+
+  ret double %t3
+}
+
 ; Unsimplified, but still valid. Also, throw in some bogus arguments.
 
 define void @gep0(i8* %unused, i8* %other, i8* %ptr) {




More information about the llvm-commits mailing list