[llvm] r367961 - [Attributor] Provide a generic interface to check live instructions

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 5 17:32:43 PDT 2019


Author: jdoerfert
Date: Mon Aug  5 17:32:43 2019
New Revision: 367961

URL: http://llvm.org/viewvc/llvm-project?rev=367961&view=rev
Log:
[Attributor] Provide a generic interface to check live instructions

Summary:
Similar to `Attributor::checkForAllCallSites`, we now provide such
functionality for instructions of a certain opcode through
`Attributor::checkForAllInstructions` and the convenient wrapper
`Attributor::checkForAllCallLikeInstructions`. This cleans up code,
avoids duplication, and simplifies the usage of liveness information.

Reviewers: sstefan1, uenoku

Subscribers: hiraditya, bollu, llvm-commits

Tags: #llvm

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

Modified:
    llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp

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=367961&r1=367960&r2=367961&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Mon Aug  5 17:32:43 2019
@@ -266,7 +266,29 @@ 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,
-                            bool RequireAllCallSites, AbstractAttribute &AA);
+                            AbstractAttribute &QueryingAA,
+                            bool RequireAllCallSites);
+
+  /// 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);
+
+  /// 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) {
+    return checkForAllInstructions(F, Pred, QueryingAA, InfoCache,
+                                   {(unsigned)Instruction::Invoke,
+                                    (unsigned)Instruction::CallBr,
+                                    (unsigned)Instruction::Call});
+  }
 
 private:
   /// The set of all abstract attributes.

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=367961&r1=367960&r2=367961&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Mon Aug  5 17:32:43 2019
@@ -422,29 +422,23 @@ ChangeStatus AANoUnwindImpl::updateImpl(
   Function &F = getAnchorScope();
 
   // The map from instruction opcodes to those instructions in the function.
-  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
   auto Opcodes = {
       (unsigned)Instruction::Invoke,      (unsigned)Instruction::CallBr,
       (unsigned)Instruction::Call,        (unsigned)Instruction::CleanupRet,
       (unsigned)Instruction::CatchSwitch, (unsigned)Instruction::Resume};
 
-  auto *LivenessAA = A.getAAFor<AAIsDead>(*this, F);
-
-  for (unsigned Opcode : Opcodes) {
-    for (Instruction *I : OpcodeInstMap[Opcode]) {
-      // Skip dead instructions.
-      if (LivenessAA && LivenessAA->isAssumedDead(I))
-        continue;
+  auto CheckForNoUnwind = [&](Instruction &I) {
+    if (!I.mayThrow())
+      return true;
 
-      if (!I->mayThrow())
-        continue;
+    auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, I);
+    return NoUnwindAA && NoUnwindAA->isAssumedNoUnwind();
+  };
 
-      auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, *I);
+  if (!A.checkForAllInstructions(F, CheckForNoUnwind, *this, InfoCache,
+                                 Opcodes))
+    return indicatePessimisticFixpoint();
 
-      if (!NoUnwindAA || !NoUnwindAA->isAssumedNoUnwind())
-        return indicatePessimisticFixpoint();
-    }
-  }
   return ChangeStatus::UNCHANGED;
 }
 
@@ -968,30 +962,18 @@ ChangeStatus AANoSyncImpl::updateImpl(At
     return indicatePessimisticFixpoint();
   }
 
-  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
-  auto Opcodes = {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
-                  (unsigned)Instruction::Call};
-
-  for (unsigned Opcode : Opcodes) {
-    for (Instruction *I : OpcodeInstMap[Opcode]) {
-      // Skip assumed dead instructions.
-      if (LivenessAA && LivenessAA->isAssumedDead(I))
-        continue;
-      // At this point we handled all read/write effects and they are all
-      // nosync, so they can be skipped.
-      if (I->mayReadOrWriteMemory())
-        continue;
-
-      ImmutableCallSite ICS(I);
-
-      // non-convergent and readnone imply nosync.
-      if (!ICS.isConvergent())
-        continue;
+  auto CheckForNoSync = [&](Instruction &I) {
+    // At this point we handled all read/write effects and they are all
+    // nosync, so they can be skipped.
+    if (I.mayReadOrWriteMemory())
+      return true;
 
-      return indicatePessimisticFixpoint();
-    }
-  }
+    // non-convergent and readnone imply nosync.
+    return !ImmutableCallSite(&I).isConvergent();
+  };
 
+  if (!A.checkForAllCallLikeInstructions(F, CheckForNoSync, *this, InfoCache))
+    return indicatePessimisticFixpoint();
   return ChangeStatus::UNCHANGED;
 }
 
@@ -1029,26 +1011,16 @@ ChangeStatus AANoFreeImpl::updateImpl(At
                                       InformationCache &InfoCache) {
   Function &F = getAnchorScope();
 
-  auto *LivenessAA = A.getAAFor<AAIsDead>(*this, F);
-
-  // The map from instruction opcodes to those instructions in the function.
-  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
+  auto CheckForNoFree = [&](Instruction &I) {
+    if (ImmutableCallSite(&I).hasFnAttr(Attribute::NoFree))
+      return true;
 
-  for (unsigned Opcode :
-       {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
-        (unsigned)Instruction::Call}) {
-    for (Instruction *I : OpcodeInstMap[Opcode]) {
-      // Skip assumed dead instructions.
-      if (LivenessAA && LivenessAA->isAssumedDead(I))
-        continue;
-      auto ICS = ImmutableCallSite(I);
-      auto *NoFreeAA = A.getAAFor<AANoFreeImpl>(*this, *I);
+    auto *NoFreeAA = A.getAAFor<AANoFreeImpl>(*this, I);
+    return NoFreeAA && NoFreeAA->isAssumedNoFree();
+  };
 
-      if ((!NoFreeAA || !NoFreeAA->isAssumedNoFree()) &&
-          !ICS.hasFnAttr(Attribute::NoFree))
-        return indicatePessimisticFixpoint();
-    }
-  }
+  if (!A.checkForAllCallLikeInstructions(F, CheckForNoFree, *this, InfoCache))
+    return indicatePessimisticFixpoint();
   return ChangeStatus::UNCHANGED;
 }
 
@@ -1215,7 +1187,7 @@ ChangeStatus AANonNullArgument::updateIm
 
     return false;
   };
-  if (!A.checkForAllCallSites(F, CallSiteCheck, true, *this))
+  if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true))
     return indicatePessimisticFixpoint();
   return ChangeStatus::UNCHANGED;
 }
@@ -1303,41 +1275,29 @@ void AAWillReturnFunction::initialize(At
 
 ChangeStatus AAWillReturnFunction::updateImpl(Attributor &A,
                                               InformationCache &InfoCache) {
-  Function &F = getAnchorScope();
-
+  const Function &F = getAnchorScope();
   // The map from instruction opcodes to those instructions in the function.
-  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
 
-  auto *LivenessAA = A.getAAFor<AAIsDead>(*this, F);
+  auto CheckForWillReturn = [&](Instruction &I) {
+    ImmutableCallSite ICS(&I);
+    if (ICS.hasFnAttr(Attribute::WillReturn))
+      return true;
 
-  for (unsigned Opcode :
-       {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
-        (unsigned)Instruction::Call}) {
-    for (Instruction *I : OpcodeInstMap[Opcode]) {
-      // Skip assumed dead instructions.
-      if (LivenessAA && LivenessAA->isAssumedDead(I))
-        continue;
+    auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, I);
+    if (!WillReturnAA || !WillReturnAA->isAssumedWillReturn())
+      return false;
 
-      auto ICS = ImmutableCallSite(I);
+    // FIXME: Prohibit any recursion for now.
+    if (ICS.hasFnAttr(Attribute::NoRecurse))
+      return true;
 
-      if (ICS.hasFnAttr(Attribute::WillReturn))
-        continue;
+    auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, I);
+    return NoRecurseAA && NoRecurseAA->isAssumedNoRecurse();
+  };
 
-      auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, *I);
-      if (!WillReturnAA || !WillReturnAA->isAssumedWillReturn())
-        return indicatePessimisticFixpoint();
-
-      auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, *I);
-
-      // FIXME: (i) Prohibit any recursion for now.
-      //        (ii) AANoRecurse isn't implemented yet so currently any call is
-      //        regarded as having recursion.
-      //       Code below should be
-      //       if ((!NoRecurseAA || !NoRecurseAA->isAssumedNoRecurse()) &&
-      if (!NoRecurseAA && !ICS.hasFnAttr(Attribute::NoRecurse))
-        return indicatePessimisticFixpoint();
-    }
-  }
+  if (!A.checkForAllCallLikeInstructions(F, CheckForWillReturn, *this,
+                                         InfoCache))
+    return indicatePessimisticFixpoint();
 
   return ChangeStatus::UNCHANGED;
 }
@@ -1969,7 +1929,7 @@ AADereferenceableArgument::updateImpl(At
     return isValidState();
   };
 
-  if (!A.checkForAllCallSites(F, CallSiteCheck, true, *this))
+  if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true))
     return indicatePessimisticFixpoint();
 
   updateAssumedNonNullGlobalState(IsNonNull, IsGlobal);
@@ -2155,7 +2115,7 @@ ChangeStatus AAAlignArgument::updateImpl
     return isValidState();
   };
 
-  if (!A.checkForAllCallSites(F, CallSiteCheck, true, *this))
+  if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true))
     indicatePessimisticFixpoint();
 
   return BeforeState == getAssumed() ? ChangeStatus::UNCHANGED
@@ -2230,21 +2190,11 @@ struct AANoReturnImpl : public AANoRetur
   /// See AbstractAttribute::updateImpl(Attributor &A).
   virtual ChangeStatus updateImpl(Attributor &A,
                                   InformationCache &InfoCache) override {
-    Function &F = getAnchorScope();
-
-    // The map from instruction opcodes to those instructions in the function.
-    auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
-
-    // Look at all return instructions.
-    auto &ReturnInsts = OpcodeInstMap[Instruction::Ret];
-    if (ReturnInsts.empty())
-      return indicateOptimisticFixpoint();
-
-    auto *LivenessAA = A.getAAFor<AAIsDead>(*this, F);
-    if (!LivenessAA ||
-        LivenessAA->isLiveInstSet(ReturnInsts.begin(), ReturnInsts.end()))
+    const Function &F = getAnchorScope();
+    auto CheckForNoReturn = [](Instruction &) { return false; };
+    if (!A.checkForAllInstructions(F, CheckForNoReturn, *this, InfoCache,
+                                   {(unsigned)Instruction::Ret}))
       return indicatePessimisticFixpoint();
-
     return ChangeStatus::UNCHANGED;
   }
 };
@@ -2259,8 +2209,8 @@ struct AANoReturnFunction final : AANoRe
 
 bool Attributor::checkForAllCallSites(Function &F,
                                       std::function<bool(CallSite)> &Pred,
-                                      bool RequireAllCallSites,
-                                      AbstractAttribute &AA) {
+                                      AbstractAttribute &QueryingAA,
+                                      bool RequireAllCallSites) {
   // We can try to determine information from
   // the call sites. However, this is only possible all call sites are known,
   // hence the function has internal linkage.
@@ -2276,7 +2226,7 @@ bool Attributor::checkForAllCallSites(Fu
     Instruction *I = cast<Instruction>(U.getUser());
     Function *AnchorValue = I->getParent()->getParent();
 
-    auto *LivenessAA = getAAFor<AAIsDead>(AA, *AnchorValue);
+    auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, *AnchorValue);
 
     // Skip dead calls.
     if (LivenessAA && LivenessAA->isAssumedDead(I))
@@ -2301,6 +2251,28 @@ bool Attributor::checkForAllCallSites(Fu
   }
 
   return true;
+}
+
+bool Attributor::checkForAllInstructions(
+    const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred,
+    AbstractAttribute &QueryingAA, InformationCache &InfoCache,
+    const ArrayRef<unsigned> &Opcodes) {
+
+  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+
+  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
+  for (unsigned Opcode : Opcodes) {
+    for (Instruction *I : OpcodeInstMap[Opcode]) {
+      // Skip dead instructions.
+      if (LivenessAA && LivenessAA->isAssumedDead(I))
+        continue;
+
+      if (!Pred(*I))
+        return false;
+    }
+  }
+
+  return true;
 }
 
 ChangeStatus Attributor::run(InformationCache &InfoCache) {




More information about the llvm-commits mailing list