[llvm] r368222 - [Attributor] Provide easier checkForallReturnedValues functionality

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 7 15:27:24 PDT 2019


Author: jdoerfert
Date: Wed Aug  7 15:27:24 2019
New Revision: 368222

URL: http://llvm.org/viewvc/llvm-project?rev=368222&view=rev
Log:
[Attributor] Provide easier checkForallReturnedValues functionality

Summary:
So far, whenever one wants to look at returned values, one had to deal
with the AAReturnedValues and potentially with the AAIsDead attribute.
In the same spirit as other checkForAllXXX methods, we add this
functionality now to the Attributor. By adopting the use sites we got
better results when return instructions were dead.

Reviewers: sstefan1, uenoku

Subscribers: hiraditya, bollu, llvm-commits

Tags: #llvm

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

Modified:
    llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp
    llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll
    llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.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=368222&r1=368221&r2=368222&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Wed Aug  7 15:27:24 2019
@@ -170,7 +170,7 @@ struct Attributor {
   /// the one reasoning about the "captured" state for the argument or the one
   /// reasoning on the memory access behavior of the function as a whole.
   template <typename AAType>
-  const AAType *getAAFor(AbstractAttribute &QueryingAA, const Value &V,
+  const AAType *getAAFor(const AbstractAttribute &QueryingAA, const Value &V,
                          int ArgNo = -1) {
     static_assert(std::is_base_of<AbstractAttribute, AAType>::value,
                   "Cannot query an attribute with a type not derived from "
@@ -199,7 +199,7 @@ struct Attributor {
       // Do not return an attribute with an invalid state. This minimizes checks
       // at the calls sites and allows the fallback below to kick in.
       if (AA->getState().isValidState()) {
-        QueryMap[AA].insert(&QueryingAA);
+        QueryMap[AA].insert(const_cast<AbstractAttribute *>(&QueryingAA));
         return AA;
       }
     }
@@ -266,24 +266,43 @@ struct Attributor {
   /// true if \p Pred holds in every call sites. However, this is only possible
   /// all call sites are known, hence the function has internal linkage.
   bool checkForAllCallSites(Function &F, std::function<bool(CallSite)> &Pred,
-                            AbstractAttribute &QueryingAA,
+                            const AbstractAttribute &QueryingAA,
                             bool RequireAllCallSites);
 
+  /// Check \p Pred on all values potentially returned by \p F.
+  ///
+  /// This method will evaluate \p Pred on all values potentially returned by
+  /// \p F associated to their respective return instructions. Return true if
+  /// \p Pred holds on all of them.
+  bool checkForAllReturnedValuesAndReturnInsts(
+      const Function &F,
+      const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)>
+          &Pred,
+      const AbstractAttribute &QueryingAA);
+
+  /// Check \p Pred on all values potentially returned by \p F.
+  ///
+  /// This is the context insensitive version of the method above.
+  bool checkForAllReturnedValues(const Function &F,
+                                 const function_ref<bool(Value &)> &Pred,
+                                 const AbstractAttribute &QueryingAA);
+
   /// Check \p Pred on all instructions with an opcode present in \p Opcodes.
   ///
   /// This method will evaluate \p Pred on all instructions with an opcode
   /// present in \p Opcode and return true if \p Pred holds on all of them.
-  bool checkForAllInstructions(
-      const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred,
-      AbstractAttribute &QueryingAA, InformationCache &InfoCache,
-      const ArrayRef<unsigned> &Opcodes);
+  bool checkForAllInstructions(const Function &F,
+                               const function_ref<bool(Instruction &)> &Pred,
+                               const AbstractAttribute &QueryingAA,
+                               InformationCache &InfoCache,
+                               const ArrayRef<unsigned> &Opcodes);
 
   /// Check \p Pred on all call-like instructions (=CallBased derived).
   ///
   /// See checkForAllCallLikeInstructions(...) for more information.
   bool checkForAllCallLikeInstructions(
-      const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred,
-      AbstractAttribute &QueryingAA, InformationCache &InfoCache) {
+      const Function &F, const function_ref<bool(Instruction &)> &Pred,
+      const AbstractAttribute &QueryingAA, InformationCache &InfoCache) {
     return checkForAllInstructions(F, Pred, QueryingAA, InfoCache,
                                    {(unsigned)Instruction::Invoke,
                                     (unsigned)Instruction::CallBr,
@@ -845,9 +864,12 @@ struct AAReturnedValues
   /// This method will evaluate \p Pred on returned values and return
   /// true if (1) all returned values are known, and (2) \p Pred returned true
   /// for all returned values.
-  virtual bool checkForallReturnedValues(
-      std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> &Pred)
-      const = 0;
+  ///
+  /// Note: Unlike the Attributor::checkForAllReturnedValuesAndReturnInsts
+  /// method, this one will not filter dead return instructions.
+  virtual bool checkForAllReturnedValuesAndReturnInsts(
+      const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)>
+          &Pred) const = 0;
 
   /// Unique ID (due to the unique address)
   static const char ID;

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=368222&r1=368221&r2=368222&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Wed Aug  7 15:27:24 2019
@@ -444,6 +444,9 @@ ChangeStatus AANoUnwindImpl::updateImpl(
 ///
 /// If there is a unique returned value R, the manifest method will:
 ///   - mark R with the "returned" attribute, if R is an argument.
+///
+/// TODO: We should use liveness during construction of the returned values map
+///       and before we set HasOverdefinedReturnedCalls.
 class AAReturnedValuesImpl : public AAReturnedValues, public AbstractState {
 
   /// Mapping of values potentially returned by the associated function to the
@@ -539,13 +542,12 @@ public:
   /// Return an assumed unique return value if a single candidate is found. If
   /// there cannot be one, return a nullptr. If it is not clear yet, return the
   /// Optional::NoneType.
-  Optional<Value *>
-  getAssumedUniqueReturnValue(const AAIsDead *LivenessAA) const;
+  Optional<Value *> getAssumedUniqueReturnValue(Attributor &A) const;
 
-  /// See AbstractState::checkForallReturnedValues(...).
-  bool checkForallReturnedValues(
-      std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> &Pred)
-      const override;
+  /// See AbstractState::checkForAllReturnedValues(...).
+  bool checkForAllReturnedValuesAndReturnInsts(
+      const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)>
+          &Pred) const override;
 
   /// Pretty print the attribute similar to the IR representation.
   const std::string getAsStr() const override;
@@ -582,10 +584,8 @@ ChangeStatus AAReturnedValuesImpl::manif
   assert(isValidState());
   NumFnKnownReturns++;
 
-  auto *LivenessAA = A.getAAFor<AAIsDead>(*this, getAnchorScope());
-
   // Check if we have an assumed unique return value that we could manifest.
-  Optional<Value *> UniqueRV = getAssumedUniqueReturnValue(LivenessAA);
+  Optional<Value *> UniqueRV = getAssumedUniqueReturnValue(A);
 
   if (!UniqueRV.hasValue() || !UniqueRV.getValue())
     return Changed;
@@ -609,23 +609,16 @@ const std::string AAReturnedValuesImpl::
          ")[OD: " + std::to_string(HasOverdefinedReturnedCalls) + "]";
 }
 
-Optional<Value *> AAReturnedValuesImpl::getAssumedUniqueReturnValue(
-    const AAIsDead *LivenessAA) const {
-  // If checkForallReturnedValues provides a unique value, ignoring potential
+Optional<Value *>
+AAReturnedValuesImpl::getAssumedUniqueReturnValue(Attributor &A) const {
+  // If checkForAllReturnedValues provides a unique value, ignoring potential
   // undef values that can also be present, it is assumed to be the actual
   // return value and forwarded to the caller of this method. If there are
   // multiple, a nullptr is returned indicating there cannot be a unique
   // returned value.
   Optional<Value *> UniqueRV;
 
-  std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> Pred =
-      [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &RetInsts) -> bool {
-    // If all ReturnInsts are dead, then ReturnValue is dead as well
-    // and can be ignored.
-    if (LivenessAA &&
-        !LivenessAA->isLiveInstSet(RetInsts.begin(), RetInsts.end()))
-      return true;
-
+  auto Pred = [&](Value &RV) -> bool {
     // If we found a second returned value and neither the current nor the saved
     // one is an undef, there is no unique returned value. Undefs are special
     // since we can pretend they have any value.
@@ -642,15 +635,15 @@ Optional<Value *> AAReturnedValuesImpl::
     return true;
   };
 
-  if (!checkForallReturnedValues(Pred))
+  if (!A.checkForAllReturnedValues(getAnchorScope(), Pred, *this))
     UniqueRV = nullptr;
 
   return UniqueRV;
 }
 
-bool AAReturnedValuesImpl::checkForallReturnedValues(
-    std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> &Pred)
-    const {
+bool AAReturnedValuesImpl::checkForAllReturnedValuesAndReturnInsts(
+    const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)>
+        &Pred) const {
   if (!isValidState())
     return false;
 
@@ -728,11 +721,8 @@ ChangeStatus AAReturnedValuesImpl::updat
       continue;
     }
 
-    auto *LivenessCSAA = A.getAAFor<AAIsDead>(*this, RetCSAA->getAnchorScope());
-
     // Try to find a assumed unique return value for the called function.
-    Optional<Value *> AssumedUniqueRV =
-        RetCSAA->getAssumedUniqueReturnValue(LivenessCSAA);
+    Optional<Value *> AssumedUniqueRV = RetCSAA->getAssumedUniqueReturnValue(A);
 
     // If no assumed unique return value was found due to the lack of
     // candidates, we may need to resolve more calls (through more update
@@ -1101,14 +1091,10 @@ ChangeStatus AANonNullReturned::updateIm
                                            InformationCache &InfoCache) {
   Function &F = getAnchorScope();
 
-  auto *AARetVal = A.getAAFor<AAReturnedValues>(*this, F);
-  if (!AARetVal)
-    return indicatePessimisticFixpoint();
-
   std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> Pred =
       this->generatePredicate(A);
 
-  if (!AARetVal->checkForallReturnedValues(Pred))
+  if (!A.checkForAllReturnedValuesAndReturnInsts(F, Pred, *this))
     return indicatePessimisticFixpoint();
   return ChangeStatus::UNCHANGED;
 }
@@ -1342,12 +1328,7 @@ ChangeStatus AANoAliasReturned::updateIm
                                            InformationCache &InfoCache) {
   Function &F = getAnchorScope();
 
-  auto *AARetValImpl = A.getAAFor<AAReturnedValuesImpl>(*this, F);
-  if (!AARetValImpl)
-    return indicatePessimisticFixpoint();
-
-  std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> Pred =
-      [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &RetInsts) -> bool {
+  auto CheckReturnValue = [&](Value &RV) -> bool {
     if (Constant *C = dyn_cast<Constant>(&RV))
       if (C->isNullValue() || isa<UndefValue>(C))
         return true;
@@ -1358,11 +1339,11 @@ ChangeStatus AANoAliasReturned::updateIm
     if (!ICS)
       return false;
 
-    auto *NoAliasAA = A.getAAFor<AANoAlias>(*this, RV);
-
-    if (!ICS.returnDoesNotAlias() &&
-        (!NoAliasAA || !NoAliasAA->isAssumedNoAlias()))
-      return false;
+    if (!ICS.returnDoesNotAlias()) {
+      auto *NoAliasAA = A.getAAFor<AANoAlias>(*this, RV);
+      if (!NoAliasAA || !NoAliasAA->isAssumedNoAlias())
+        return false;
+    }
 
     /// FIXME: We can improve capture check in two ways:
     /// 1. Use the AANoCapture facilities.
@@ -1374,7 +1355,7 @@ ChangeStatus AANoAliasReturned::updateIm
     return true;
   };
 
-  if (!AARetValImpl->checkForallReturnedValues(Pred))
+  if (!A.checkForAllReturnedValues(F, CheckReturnValue, *this))
     return indicatePessimisticFixpoint();
 
   return ChangeStatus::UNCHANGED;
@@ -1853,21 +1834,16 @@ AADereferenceableReturned::updateImpl(At
 
   syncNonNull(A.getAAFor<AANonNull>(*this, F));
 
-  auto *AARetVal = A.getAAFor<AAReturnedValues>(*this, F);
-  if (!AARetVal)
-    return indicatePessimisticFixpoint();
-
   bool IsNonNull = isAssumedNonNull();
   bool IsGlobal = isAssumedGlobal();
 
-  std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> Pred =
-      [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &RetInsts) -> bool {
+  auto CheckReturnValue = [&](Value &RV) -> bool {
     takeAssumedDerefBytesMinimum(
         computeAssumedDerefenceableBytes(A, RV, IsNonNull, IsGlobal));
     return isValidState();
   };
 
-  if (AARetVal->checkForallReturnedValues(Pred)) {
+  if (A.checkForAllReturnedValues(F, CheckReturnValue, *this)) {
     updateAssumedNonNullGlobalState(IsNonNull, IsGlobal);
     return BeforeState == static_cast<DerefState>(*this)
                ? ChangeStatus::UNCHANGED
@@ -2035,9 +2011,6 @@ struct AAAlignReturned final : AAAlignIm
 ChangeStatus AAAlignReturned::updateImpl(Attributor &A,
                                          InformationCache &InfoCache) {
   Function &F = getAnchorScope();
-  auto *AARetValImpl = A.getAAFor<AAReturnedValuesImpl>(*this, F);
-  if (!AARetValImpl)
-    return indicatePessimisticFixpoint();
 
   // Currently, align<n> is deduced if alignments in return values are assumed
   // as greater than n. We reach pessimistic fixpoint if any of the return value
@@ -2045,7 +2018,7 @@ ChangeStatus AAAlignReturned::updateImpl
   // optimistic fixpoint is reached earlier.
 
   base_t BeforeState = getAssumed();
-  std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> Pred =
+  auto CheckReturnValue =
       [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &RetInsts) -> bool {
     auto *AlignAA = A.getAAFor<AAAlign>(*this, RV);
 
@@ -2059,7 +2032,7 @@ ChangeStatus AAAlignReturned::updateImpl
     return isValidState();
   };
 
-  if (!AARetValImpl->checkForallReturnedValues(Pred))
+  if (!A.checkForAllReturnedValuesAndReturnInsts(F, CheckReturnValue, *this))
     return indicatePessimisticFixpoint();
 
   return (getAssumed() != BeforeState) ? ChangeStatus::CHANGED
@@ -2201,7 +2174,7 @@ struct AANoReturnFunction final : AANoRe
 
 bool Attributor::checkForAllCallSites(Function &F,
                                       std::function<bool(CallSite)> &Pred,
-                                      AbstractAttribute &QueryingAA,
+                                      const AbstractAttribute &QueryingAA,
                                       bool RequireAllCallSites) {
   // We can try to determine information from
   // the call sites. However, this is only possible all call sites are known,
@@ -2245,9 +2218,62 @@ bool Attributor::checkForAllCallSites(Fu
   return true;
 }
 
+bool Attributor::checkForAllReturnedValuesAndReturnInsts(
+    const Function &F,
+    const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)>
+        &Pred,
+    const AbstractAttribute &QueryingAA) {
+
+  auto *AARetVal = getAAFor<AAReturnedValues>(QueryingAA, F);
+  if (!AARetVal)
+    return false;
+
+  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+  if (!LivenessAA)
+    return AARetVal->checkForAllReturnedValuesAndReturnInsts(Pred);
+
+  auto LivenessFilter = [&](Value &RV,
+                            const SmallPtrSetImpl<ReturnInst *> &ReturnInsts) {
+    SmallPtrSet<ReturnInst *, 4> FilteredReturnInsts;
+    for (ReturnInst *RI : ReturnInsts)
+      if (!LivenessAA->isAssumedDead(RI))
+        FilteredReturnInsts.insert(RI);
+    if (!FilteredReturnInsts.empty())
+      return Pred(RV, FilteredReturnInsts);
+    return true;
+  };
+
+  return AARetVal->checkForAllReturnedValuesAndReturnInsts(LivenessFilter);
+}
+
+bool Attributor::checkForAllReturnedValues(
+    const Function &F, const function_ref<bool(Value &)> &Pred,
+    const AbstractAttribute &QueryingAA) {
+
+  auto *AARetVal = getAAFor<AAReturnedValues>(QueryingAA, F);
+  if (!AARetVal)
+    return false;
+
+  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+  if (!LivenessAA)
+    return AARetVal->checkForAllReturnedValuesAndReturnInsts(
+        [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &) {
+          return Pred(RV);
+        });
+
+  auto LivenessFilter = [&](Value &RV,
+                            const SmallPtrSetImpl<ReturnInst *> &ReturnInsts) {
+    if (LivenessAA->isLiveInstSet(ReturnInsts.begin(), ReturnInsts.end()))
+      return Pred(RV);
+    return true;
+  };
+
+  return AARetVal->checkForAllReturnedValuesAndReturnInsts(LivenessFilter);
+}
+
 bool Attributor::checkForAllInstructions(
     const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred,
-    AbstractAttribute &QueryingAA, InformationCache &InfoCache,
+    const AbstractAttribute &QueryingAA, InformationCache &InfoCache,
     const ArrayRef<unsigned> &Opcodes) {
 
   auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);

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=368222&r1=368221&r2=368222&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll Wed Aug  7 15:27:24 2019
@@ -66,7 +66,7 @@ return:
 ;   return 0;
 ; }
 ;
-; CHECK: define noalias double* @srec0(double* nocapture readnone %a)
+; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) double* @srec0(double* nocapture readnone %a)
 define double* @srec0(double* %a) #0 {
 entry:
   %call = call double* @srec0(double* %a)

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=368222&r1=368221&r2=368222&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll Wed Aug  7 15:27:24 2019
@@ -261,7 +261,7 @@ return:
 ;
 ; FNATTR:  define i32* @rt0(i32* readonly %a)
 ; BOTH: Function Attrs: nofree noinline noreturn nosync nounwind readonly uwtable
-; BOTH-NEXT:    define i32* @rt0(i32* readonly %a)
+; BOTH-NEXT:    define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* readonly %a)
 define i32* @rt0(i32* %a) #0 {
 entry:
   %v = load i32, i32* %a, align 4
@@ -279,7 +279,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 i32* @rt1(i32* nocapture readonly %a)
+; BOTH-NEXT:    define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture readonly %a)
 define i32* @rt1(i32* %a) #0 {
 entry:
   %v = load i32, i32* %a, align 4




More information about the llvm-commits mailing list