[llvm] r370917 - [Attributor] Deal more explicit with non-exact definitions

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 4 09:16:13 PDT 2019


Author: jdoerfert
Date: Wed Sep  4 09:16:13 2019
New Revision: 370917

URL: http://llvm.org/viewvc/llvm-project?rev=370917&view=rev
Log:
[Attributor] Deal more explicit with non-exact definitions

Summary:
Before we tried to rule out non-exact definitions early but that lead to
on-demand attributes created for them anyway. As a consequence we needed
to look at the definition in the initialize of each attribute again.
This patch centralized this lookup and tightens the condition under
which we give up on non-exact definitions.

Reviewers: uenoku, sstefan1

Subscribers: hiraditya, bollu, llvm-commits

Tags: #llvm

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

Modified:
    llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp
    llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
    llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nounwind.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=370917&r1=370916&r2=370917&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Wed Sep  4 09:16:13 2019
@@ -289,6 +289,19 @@ struct IRPosition {
   }
   ///}
 
+  /// Return true if the position refers to a function interface, that is the
+  /// function scope, the function return, or an argumnt.
+  bool isFnInterfaceKind() const {
+    switch (getPositionKind()) {
+    case IRPosition::IRP_FUNCTION:
+    case IRPosition::IRP_RETURNED:
+    case IRPosition::IRP_ARGUMENT:
+      return true;
+    default:
+      return false;
+    }
+  }
+
   /// Return the Function surrounding the anchor value.
   ///
   ///{
@@ -1035,6 +1048,27 @@ struct IRAttribute : public IRPosition,
   IRAttribute(const IRPosition &IRP) : IRPosition(IRP) {}
   ~IRAttribute() {}
 
+  /// See AbstractAttribute::initialize(...).
+  virtual void initialize(Attributor &A) override {
+    if (hasAttr(getAttrKind())) {
+      this->getState().indicateOptimisticFixpoint();
+      return;
+    }
+
+    const IRPosition &IRP = this->getIRPosition();
+    bool IsFnInterface = IRP.isFnInterfaceKind();
+    const Function *FnScope = IRP.getAnchorScope();
+    // TODO: Not all attributes require an exact definition. Find a way to
+    //       enable deduction for some but not all attributes in case the
+    //       definition might be changed at runtime, see also
+    //       http://lists.llvm.org/pipermail/llvm-dev/2018-February/121275.html.
+    // TODO: We could always determine abstract attributes and if sufficient
+    //       information was found we could duplicate the functions that do not
+    //       have an exact definition.
+    if (IsFnInterface && (!FnScope || !FnScope->hasExactDefinition()))
+      this->getState().indicatePessimisticFixpoint();
+  }
+
   /// See AbstractAttribute::manifest(...).
   ChangeStatus manifest(Attributor &A) override {
     SmallVector<Attribute, 4> DeducedAttrs;

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=370917&r1=370916&r2=370917&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Wed Sep  4 09:16:13 2019
@@ -646,12 +646,6 @@ struct AACallSiteReturnedFromReturned :
 struct AANoUnwindImpl : AANoUnwind {
   AANoUnwindImpl(const IRPosition &IRP) : AANoUnwind(IRP) {}
 
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    if (hasAttr({Attribute::NoUnwind}))
-      indicateOptimisticFixpoint();
-  }
-
   const std::string getAsStr() const override {
     return getAssumed() ? "nounwind" : "may-unwind";
   }
@@ -697,7 +691,7 @@ struct AANoUnwindCallSite final : AANoUn
   void initialize(Attributor &A) override {
     AANoUnwindImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -757,7 +751,7 @@ public:
     ReturnedValues.clear();
 
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition()) {
+    if (!F) {
       indicatePessimisticFixpoint();
       return;
     }
@@ -776,6 +770,9 @@ public:
         return;
       }
     }
+
+    if (!F->hasExactDefinition())
+      indicatePessimisticFixpoint();
   }
 
   /// See AbstractAttribute::manifest(...).
@@ -1142,12 +1139,6 @@ struct AAReturnedValuesCallSite final :
 struct AANoSyncImpl : AANoSync {
   AANoSyncImpl(const IRPosition &IRP) : AANoSync(IRP) {}
 
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    if (hasAttr({Attribute::NoSync}))
-      indicateOptimisticFixpoint();
-  }
-
   const std::string getAsStr() const override {
     return getAssumed() ? "nosync" : "may-sync";
   }
@@ -1315,7 +1306,7 @@ struct AANoSyncCallSite final : AANoSync
   void initialize(Attributor &A) override {
     AANoSyncImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -1341,12 +1332,6 @@ struct AANoSyncCallSite final : AANoSync
 struct AANoFreeImpl : public AANoFree {
   AANoFreeImpl(const IRPosition &IRP) : AANoFree(IRP) {}
 
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    if (hasAttr({Attribute::NoFree}))
-      indicateOptimisticFixpoint();
-  }
-
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override {
     auto CheckForNoFree = [&](Instruction &I) {
@@ -1385,7 +1370,7 @@ struct AANoFreeCallSite final : AANoFree
   void initialize(Attributor &A) override {
     AANoFreeImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -1414,6 +1399,8 @@ struct AANonNullImpl : AANonNull {
   void initialize(Attributor &A) override {
     if (hasAttr({Attribute::NonNull, Attribute::Dereferenceable}))
       indicateOptimisticFixpoint();
+    else
+      AANonNull::initialize(A);
   }
 
   /// See AbstractAttribute::getAsStr().
@@ -1519,14 +1506,6 @@ struct AANonNullCallSiteReturned final
 struct AANoRecurseImpl : public AANoRecurse {
   AANoRecurseImpl(const IRPosition &IRP) : AANoRecurse(IRP) {}
 
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    if (hasAttr({getAttrKind()})) {
-      indicateOptimisticFixpoint();
-      return;
-    }
-  }
-
   /// See AbstractAttribute::getAsStr()
   const std::string getAsStr() const override {
     return getAssumed() ? "norecurse" : "may-recurse";
@@ -1553,7 +1532,7 @@ struct AANoRecurseCallSite final : AANoR
   void initialize(Attributor &A) override {
     AANoRecurseImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -1606,10 +1585,7 @@ struct AAWillReturnImpl : public AAWillR
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    if (hasAttr({Attribute::WillReturn})) {
-      indicateOptimisticFixpoint();
-      return;
-    }
+    AAWillReturn::initialize(A);
 
     Function *F = getAssociatedFunction();
     if (containsPossiblyEndlessLoop(F))
@@ -1656,7 +1632,7 @@ struct AAWillReturnCallSite final : AAWi
   void initialize(Attributor &A) override {
     AAWillReturnImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -1683,12 +1659,6 @@ struct AAWillReturnCallSite final : AAWi
 struct AANoAliasImpl : AANoAlias {
   AANoAliasImpl(const IRPosition &IRP) : AANoAlias(IRP) {}
 
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    if (hasAttr({Attribute::NoAlias}))
-      indicateOptimisticFixpoint();
-  }
-
   const std::string getAsStr() const override {
     return getAssumed() ? "noalias" : "may-alias";
   }
@@ -1792,7 +1762,7 @@ struct AANoAliasCallSiteReturned final :
   void initialize(Attributor &A) override {
     AANoAliasImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -2186,6 +2156,12 @@ struct AADereferenceableImpl : AADerefer
       takeKnownDerefBytesMaximum(Attr.getValueAsInt());
 
     NonNullAA = &A.getAAFor<AANonNull>(*this, getIRPosition());
+
+    const IRPosition &IRP = this->getIRPosition();
+    bool IsFnInterface = IRP.isFnInterfaceKind();
+    const Function *FnScope = IRP.getAnchorScope();
+    if (IsFnInterface && (!FnScope || !FnScope->hasExactDefinition()))
+      indicatePessimisticFixpoint();
   }
 
   /// See AbstractAttribute::getState()
@@ -2340,7 +2316,7 @@ struct AADereferenceableCallSiteReturned
   void initialize(Attributor &A) override {
     AADereferenceableImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -2508,7 +2484,7 @@ struct AAAlignCallSiteReturned final : A
   void initialize(Attributor &A) override {
     AAAlignImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -2538,12 +2514,6 @@ struct AANoReturnImpl : public AANoRetur
     return getAssumed() ? "noreturn" : "may-return";
   }
 
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    if (hasAttr({getAttrKind()}))
-      indicateOptimisticFixpoint();
-  }
-
   /// See AbstractAttribute::updateImpl(Attributor &A).
   virtual ChangeStatus updateImpl(Attributor &A) override {
     auto CheckForNoReturn = [](Instruction &) { return false; };
@@ -2569,7 +2539,7 @@ struct AANoReturnCallSite final : AANoRe
   void initialize(Attributor &A) override {
     AANoReturnImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F)
       indicatePessimisticFixpoint();
   }
 
@@ -2599,10 +2569,7 @@ struct AANoCaptureImpl : public AANoCapt
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    if (hasAttr(Attribute::NoCapture)) {
-      indicateOptimisticFixpoint();
-      return;
-    }
+    AANoCapture::initialize(A);
 
     const IRPosition &IRP = getIRPosition();
     const Function *F =
@@ -2611,8 +2578,7 @@ struct AANoCaptureImpl : public AANoCapt
     // Check what state the associated function can actually capture.
     if (F)
       determineFunctionCaptureCapabilities(*F, *this);
-
-    if (!F || !F->hasExactDefinition())
+    else
       indicatePessimisticFixpoint();
   }
 
@@ -2999,7 +2965,7 @@ bool Attributor::checkForAllCallSites(co
     }
 
     CallSite CS(U.getUser());
-    if (!CS || !CS.isCallee(&U) || !CS.getCaller()->hasExactDefinition()) {
+    if (!CS || !CS.isCallee(&U)) {
       if (!RequireAllCallSites)
         continue;
 
@@ -3029,7 +2995,7 @@ bool Attributor::checkForAllReturnedValu
   // Since we need to provide return instructions we have to have an exact
   // definition.
   const Function *AssociatedFunction = IRP.getAssociatedFunction();
-  if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition())
+  if (!AssociatedFunction)
     return false;
 
   // If this is a call site query we use the call site specific return values
@@ -3049,7 +3015,7 @@ bool Attributor::checkForAllReturnedValu
 
   const IRPosition &IRP = QueryingAA.getIRPosition();
   const Function *AssociatedFunction = IRP.getAssociatedFunction();
-  if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition())
+  if (!AssociatedFunction)
     return false;
 
   // TODO: use the function scope once we have call site AAReturnedValues.
@@ -3071,7 +3037,7 @@ bool Attributor::checkForAllInstructions
   const IRPosition &IRP = QueryingAA.getIRPosition();
   // Since we need to provide instructions we have to have an exact definition.
   const Function *AssociatedFunction = IRP.getAssociatedFunction();
-  if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition())
+  if (!AssociatedFunction)
     return false;
 
   // TODO: use the function scope once we have call site AAReturnedValues.
@@ -3576,25 +3542,16 @@ static bool runAttributorOnModule(Module
   Attributor A(InfoCache, DepRecInterval);
 
   for (Function &F : M) {
-    // TODO: Not all attributes require an exact definition. Find a way to
-    //       enable deduction for some but not all attributes in case the
-    //       definition might be changed at runtime, see also
-    //       http://lists.llvm.org/pipermail/llvm-dev/2018-February/121275.html.
-    // TODO: We could always determine abstract attributes and if sufficient
-    //       information was found we could duplicate the functions that do not
-    //       have an exact definition.
-    if (!F.hasExactDefinition()) {
+    if (F.hasExactDefinition())
+      NumFnWithExactDefinition++;
+    else
       NumFnWithoutExactDefinition++;
-      continue;
-    }
 
     // For now we ignore naked and optnone functions.
     if (F.hasFnAttribute(Attribute::Naked) ||
         F.hasFnAttribute(Attribute::OptimizeNone))
       continue;
 
-    NumFnWithExactDefinition++;
-
     // Populate the Attributor with abstract attribute opportunities in the
     // function and the information cache with IR information.
     A.identifyDefaultAbstractAttributes(F);

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=370917&r1=370916&r2=370917&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll Wed Sep  4 09:16:13 2019
@@ -796,6 +796,36 @@ r:
   ret i32 %PHI2
 }
 
+define weak_odr i32 @non_exact_0() {
+  ret i32 0
+}
+define weak_odr i32 @non_exact_1(i32 %a) {
+  ret i32 %a
+}
+define weak_odr i32 @non_exact_2(i32 returned %a) {
+  ret i32 %a
+}
+define weak_odr i32* @non_exact_3(i32* align 32 returned %a) {
+  ret i32* %a
+}
+define i32 @exact(i32* %a) {
+  %c0 = call i32 @non_exact_0()
+  %c1 = call i32 @non_exact_1(i32 1)
+  %c2 = call i32 @non_exact_2(i32 2)
+  %c3 = call i32* @non_exact_3(i32* %a)
+; We can use the information of the weak function non_exact_3 because it was
+; given to us and not derived (the alignment of the returned argument).
+; CHECK:  %c4 = load i32, i32* %c3, align 32
+  %c4 = load i32, i32* %c3
+; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1!
+; CHECK:  %add1 = add i32 %c0, %c1
+; CHECK:  %add2 = add i32 %add1, %c2
+; CHECK:  %add3 = add i32 %add2, %c3
+  %add1 = add i32 %c0, %c1
+  %add2 = add i32 %add1, %c2
+  %add3 = add i32 %add2, %c4
+  ret i32 %add3
+}
 
 attributes #0 = { noinline nounwind uwtable }
 

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll?rev=370917&r1=370916&r2=370917&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll Wed Sep  4 09:16:13 2019
@@ -458,4 +458,16 @@ define  i32* @g1() {
   ret i32* %c
 }
 
+; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull %a)
+define internal void @called_by_weak(i32* %a) {
+  ret void
+}
+
+; Check we do not annotate the function interface of this weak function.
+; ATTRIBUTOR: define weak_odr void @weak_caller(i32* nonnull %a)
+define weak_odr void @weak_caller(i32* nonnull %a) {
+  call void @called_by_weak(i32* %a)
+  ret void
+}
+
 attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll?rev=370917&r1=370916&r2=370917&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll Wed Sep  4 09:16:13 2019
@@ -1,4 +1,4 @@
-; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 -S < %s | FileCheck %s
+; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S < %s | FileCheck %s
 ;
 ; This file is the same as noreturn_sync.ll but with a personality which
 ; indicates that the exception handler *can* catch asynchronous exceptions. As

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll?rev=370917&r1=370916&r2=370917&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll Wed Sep  4 09:16:13 2019
@@ -1,5 +1,5 @@
 ; RUN: opt < %s -functionattrs -S | FileCheck %s
-; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S | FileCheck %s --check-prefix=ATTRIBUTOR
+; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 -S | FileCheck %s --check-prefix=ATTRIBUTOR
 
 ; TEST 1
 ; CHECK: Function Attrs: norecurse nounwind readnone




More information about the llvm-commits mailing list