<div dir="ltr">Hello Chandler,<br><br>This commit added warning to some builders:<br><br>PassManager.h(803): warning C4661: 'bool llvm::InnerAnalysisManagerProxy<llvm::FunctionAnalysisManager,llvm::LazyCallGraph::SCC,llvm::LazyCallGraph &>::Result::invalidate(IRUnitT &,const llvm::PreservedAnalyses &,llvm::AnalysisManager<IRUnitT,llvm::LazyCallGraph &>::Invalidator &)': no suitable definition provided for explicit template instantiation request<br><br><a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/2937">http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/2937</a><br><br>Please have a look at this?<br><br>Thanks<br><br>Galina<br><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Dec 9, 2016 at 10:34 PM, Chandler Carruth via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: chandlerc<br>
Date: Sat Dec 10 00:34:44 2016<br>
New Revision: 289317<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=289317&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=289317&view=rev</a><br>
Log:<br>
[PM] Support invalidation of inner analysis managers from a pass over the outer IR unit.<br>
<br>
Summary:<br>
This never really got implemented, and was very hard to test before<br>
a lot of the refactoring changes to make things more robust. But now we<br>
can test it thoroughly and cleanly, especially at the CGSCC level.<br>
<br>
The core idea is that when an inner analysis manager proxy receives the<br>
invalidation event for the outer IR unit, it needs to walk the inner IR<br>
units and propagate it to the inner analysis manager for each of those<br>
units. For example, each function in the SCC needs to get an<br>
invalidation event when the SCC gets one.<br>
<br>
The function / module interaction is somewhat boring here. This really<br>
becomes interesting in the face of analysis-backed IR units. This patch<br>
effectively handles all of the CGSCC layer's needs -- both invalidating<br>
SCC analysis and invalidating function analysis when an SCC gets<br>
invalidated.<br>
<br>
However, this second aspect doesn't really handle the<br>
LoopAnalysisManager well at this point. That one will need some change<br>
of design in order to fully integrate, because unlike the call graph,<br>
the entire function behind a LoopAnalysis's results can vanish out from<br>
under us, and we won't even have a cached API to access. I'd like to try<br>
to separate solving the loop problems into a subsequent patch though in<br>
order to keep this more focused so I've adapted them to the API and<br>
updated the tests that immediately fail, but I've not added the level of<br>
testing and validation at that layer that I have at the CGSCC layer.<br>
<br>
An important aspect of this change is that the proxy for the<br>
FunctionAnalysisManager at the SCC pass layer doesn't work like the<br>
other proxies for an inner IR unit as it doesn't directly manage the<br>
FunctionAnalysisManager and invalidation or clearing of it. This would<br>
create an ever worsening problem of dual ownership of this<br>
responsibility, split between the module-level FAM proxy and this<br>
SCC-level FAM proxy. Instead, this patch changes the SCC-level FAM proxy<br>
to work in terms of the module-level proxy and defer to it to handle<br>
much of the updates. It only does SCC-specific invalidation. This will<br>
become more important in subsequent patches that support more complex<br>
invalidaiton scenarios.<br>
<br>
Reviewers: jlebar<br>
<br>
Subscribers: mehdi_amini, mcrosier, mzolotukhin, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D27197" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D27197</a><br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/<wbr>Analysis/CGSCCPassManager.h<br>
    llvm/trunk/include/llvm/<wbr>Analysis/LoopPassManager.h<br>
    llvm/trunk/include/llvm/IR/<wbr>PassManager.h<br>
    llvm/trunk/lib/Analysis/<wbr>CGSCCPassManager.cpp<br>
    llvm/trunk/lib/Analysis/<wbr>LoopPassManager.cpp<br>
    llvm/trunk/lib/IR/PassManager.<wbr>cpp<br>
    llvm/trunk/lib/Passes/<wbr>PassBuilder.cpp<br>
    llvm/trunk/lib/Passes/<wbr>PassRegistry.def<br>
    llvm/trunk/test/Other/new-<wbr>pass-manager.ll<br>
    llvm/trunk/unittests/Analysis/<wbr>CGSCCPassManagerTest.cpp<br>
    llvm/trunk/unittests/IR/<wbr>PassManagerTest.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/<wbr>Analysis/CGSCCPassManager.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/include/<wbr>llvm/Analysis/<wbr>CGSCCPassManager.h?rev=289317&<wbr>r1=289316&r2=289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/<wbr>Analysis/CGSCCPassManager.h (original)<br>
+++ llvm/trunk/include/llvm/<wbr>Analysis/CGSCCPassManager.h Sat Dec 10 00:34:44 2016<br>
@@ -145,13 +145,51 @@ struct RequireAnalysisPass<AnalysisT, La<br>
   }<br>
 };<br>
<br>
-extern template class InnerAnalysisManagerProxy<<wbr>CGSCCAnalysisManager, Module>;<br>
 /// A proxy from a \c CGSCCAnalysisManager to a \c Module.<br>
 typedef InnerAnalysisManagerProxy<<wbr>CGSCCAnalysisManager, Module><br>
     CGSCCAnalysisManagerModuleProx<wbr>y;<br>
<br>
-extern template class OuterAnalysisManagerProxy<<wbr>ModuleAnalysisManager,<br>
-                                                LazyCallGraph::SCC>;<br>
+/// We need a specialized result for the \c CGSCCAnalysisManagerModuleProx<wbr>y so<br>
+/// it can have access to the call graph in order to walk all the SCCs when<br>
+/// invalidating things.<br>
+template <> class CGSCCAnalysisManagerModuleProx<wbr>y::Result {<br>
+public:<br>
+  explicit Result(CGSCCAnalysisManager &InnerAM, LazyCallGraph &G)<br>
+      : InnerAM(&InnerAM), G(&G) {}<br>
+<br>
+  /// \brief Accessor for the analysis manager.<br>
+  CGSCCAnalysisManager &getManager() { return *InnerAM; }<br>
+<br>
+  /// \brief Handler for invalidation of the Module.<br>
+  ///<br>
+  /// If the proxy analysis itself is preserved, then we assume that the set of<br>
+  /// SCCs in the Module hasn't changed. Thus any pointers to SCCs in the<br>
+  /// CGSCCAnalysisManager are still valid, and we don't need to call \c clear<br>
+  /// on the CGSCCAnalysisManager.<br>
+  ///<br>
+  /// Regardless of whether this analysis is marked as preserved, all of the<br>
+  /// analyses in the \c CGSCCAnalysisManager are potentially invalidated based<br>
+  /// on the set of preserved analyses.<br>
+  bool invalidate(Module &M, const PreservedAnalyses &PA,<br>
+                  ModuleAnalysisManager::<wbr>Invalidator &Inv);<br>
+<br>
+private:<br>
+  CGSCCAnalysisManager *InnerAM;<br>
+  LazyCallGraph *G;<br>
+};<br>
+<br>
+/// Provide a specialized run method for the \c CGSCCAnalysisManagerModuleProx<wbr>y<br>
+/// so it can pass the lazy call graph to the result.<br>
+template <><br>
+<wbr>CGSCCAnalysisManagerModuleProx<wbr>y::Result<br>
+<wbr>CGSCCAnalysisManagerModuleProx<wbr>y::run(Module &M, ModuleAnalysisManager &AM);<br>
+<br>
+// Ensure the \c CGSCCAnalysisManagerModuleProx<wbr>y is provided as an extern<br>
+// template.<br>
+extern template class InnerAnalysisManagerProxy<<wbr>CGSCCAnalysisManager, Module>;<br>
+<br>
+extern template class OuterAnalysisManagerProxy<<br>
+    ModuleAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>;<br>
 /// A proxy from a \c ModuleAnalysisManager to an \c SCC.<br>
 typedef OuterAnalysisManagerProxy<<wbr>ModuleAnalysisManager, LazyCallGraph::SCC,<br>
                                   LazyCallGraph &><br>
@@ -387,12 +425,12 @@ public:<br>
       } while (!RCWorklist.empty());<br>
     }<br>
<br>
-    // By definition we preserve the proxy. We also preserve all analyses on<br>
-    // SCCs. This precludes *any* invalidation of CGSCC analyses by the proxy,<br>
-    // but that's OK because we've taken care to invalidate analyses in the<br>
-    // CGSCC analysis manager incrementally above.<br>
+    // By definition we preserve the call garph, all SCC analyses, and the<br>
+    // analysis proxies by handling them above and in any nested pass managers.<br>
+    PA.preserve<<wbr>LazyCallGraphAnalysis>();<br>
     PA.preserve<AllAnalysesOn<<wbr>LazyCallGraph::SCC>>();<br>
     PA.preserve<<wbr>CGSCCAnalysisManagerModuleProx<wbr>y>();<br>
+    PA.preserve<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>();<br>
     return PA;<br>
   }<br>
<br>
@@ -409,12 +447,43 @@ createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(<br>
   return ModuleToPostOrderCGSCCPassAdap<wbr>tor<CGSCCPassT>(std::move(<wbr>Pass), DebugLogging);<br>
 }<br>
<br>
-extern template class InnerAnalysisManagerProxy<<wbr>FunctionAnalysisManager,<br>
-                                                LazyCallGraph::SCC>;<br>
 /// A proxy from a \c FunctionAnalysisManager to an \c SCC.<br>
-typedef InnerAnalysisManagerProxy<<wbr>FunctionAnalysisManager, LazyCallGraph::SCC,<br>
-                                  LazyCallGraph &><br>
-    FunctionAnalysisManagerCGSCCPr<wbr>oxy;<br>
+///<br>
+/// When a module pass runs and triggers invalidation, both the CGSCC and<br>
+/// Function analysis manager proxies on the module get an invalidation event.<br>
+/// We don't want to fully duplicate responsibility for most of the<br>
+/// invalidation logic. Instead, this layer is only responsible for SCC-local<br>
+/// invalidation events. We work with the module's FunctionAnalysisManager to<br>
+/// invalidate function analyses.<br>
+class FunctionAnalysisManagerCGSCCPr<wbr>oxy<br>
+    : public AnalysisInfoMixin<<wbr>FunctionAnalysisManagerCGSCCPr<wbr>oxy> {<br>
+public:<br>
+  class Result {<br>
+  public:<br>
+    explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {}<br>
+<br>
+    /// \brief Accessor for the analysis manager.<br>
+    FunctionAnalysisManager &getManager() { return *FAM; }<br>
+<br>
+    bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,<br>
+                    CGSCCAnalysisManager::<wbr>Invalidator &Inv);<br>
+<br>
+  private:<br>
+    FunctionAnalysisManager *FAM;<br>
+  };<br>
+<br>
+  /// Computes the \c FunctionAnalysisManager and stores it in the result proxy.<br>
+  Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &);<br>
+<br>
+private:<br>
+  friend AnalysisInfoMixin<<wbr>FunctionAnalysisManagerCGSCCPr<wbr>oxy>;<br>
+  static AnalysisKey Key;<br>
+};<br>
+<br>
+// Ensure the \c FunctionAnalysisManagerCGSCCPr<wbr>oxy is provided as an extern<br>
+// template.<br>
+extern template class InnerAnalysisManagerProxy<<br>
+    FunctionAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>;<br>
<br>
 extern template class OuterAnalysisManagerProxy<<wbr>CGSCCAnalysisManager, Function>;<br>
 /// A proxy from a \c CGSCCAnalysisManager to a \c Function.<br>
<br>
Modified: llvm/trunk/include/llvm/<wbr>Analysis/LoopPassManager.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopPassManager.h?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/include/<wbr>llvm/Analysis/LoopPassManager.<wbr>h?rev=289317&r1=289316&r2=<wbr>289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/<wbr>Analysis/LoopPassManager.h (original)<br>
+++ llvm/trunk/include/llvm/<wbr>Analysis/LoopPassManager.h Sat Dec 10 00:34:44 2016<br>
@@ -38,11 +38,21 @@ extern template class AnalysisManager<Lo<br>
 /// pass manager infrastructure.<br>
 typedef AnalysisManager<Loop> LoopAnalysisManager;<br>
<br>
-extern template class InnerAnalysisManagerProxy<<wbr>LoopAnalysisManager, Function>;<br>
 /// A proxy from a \c LoopAnalysisManager to a \c Function.<br>
 typedef InnerAnalysisManagerProxy<<wbr>LoopAnalysisManager, Function><br>
     LoopAnalysisManagerFunctionPro<wbr>xy;<br>
<br>
+/// Specialization of the invalidate method for the \c<br>
+/// LoopAnalysisManagerFunctionPro<wbr>xy's result.<br>
+template <><br>
+bool LoopAnalysisManagerFunctionPro<wbr>xy::Result::invalidate(<br>
+    Function &F, const PreservedAnalyses &PA,<br>
+    FunctionAnalysisManager::<wbr>Invalidator &Inv);<br>
+<br>
+// Ensure the \c LoopAnalysisManagerFunctionPro<wbr>xy is provided as an extern<br>
+// template.<br>
+extern template class InnerAnalysisManagerProxy<<wbr>LoopAnalysisManager, Function>;<br>
+<br>
 extern template class OuterAnalysisManagerProxy<<wbr>FunctionAnalysisManager, Loop>;<br>
 /// A proxy from a \c FunctionAnalysisManager to a \c Loop.<br>
 typedef OuterAnalysisManagerProxy<<wbr>FunctionAnalysisManager, Loop><br>
<br>
Modified: llvm/trunk/include/llvm/IR/<wbr>PassManager.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/PassManager.h?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/include/<wbr>llvm/IR/PassManager.h?rev=<wbr>289317&r1=289316&r2=289317&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/IR/<wbr>PassManager.h (original)<br>
+++ llvm/trunk/include/llvm/IR/<wbr>PassManager.h Sat Dec 10 00:34:44 2016<br>
@@ -750,63 +750,61 @@ class InnerAnalysisManagerProxy<br>
 public:<br>
   class Result {<br>
   public:<br>
-    explicit Result(AnalysisManagerT &AM) : AM(&AM) {}<br>
-    Result(Result &&Arg) : AM(std::move(Arg.AM)) {<br>
+    explicit Result(AnalysisManagerT &InnerAM) : InnerAM(&InnerAM) {}<br>
+    Result(Result &&Arg) : InnerAM(std::move(Arg.InnerAM)<wbr>) {<br>
       // We have to null out the analysis manager in the moved-from state<br>
       // because we are taking ownership of the responsibilty to clear the<br>
       // analysis state.<br>
-      Arg.AM = nullptr;<br>
+      Arg.InnerAM = nullptr;<br>
     }<br>
     Result &operator=(Result &&RHS) {<br>
-      AM = <a href="http://RHS.AM" rel="noreferrer" target="_blank">RHS.AM</a>;<br>
+      InnerAM = RHS.InnerAM;<br>
       // We have to null out the analysis manager in the moved-from state<br>
       // because we are taking ownership of the responsibilty to clear the<br>
       // analysis state.<br>
-      <a href="http://RHS.AM" rel="noreferrer" target="_blank">RHS.AM</a> = nullptr;<br>
+      RHS.InnerAM = nullptr;<br>
       return *this;<br>
     }<br>
     ~Result() {<br>
-      // AM is cleared in a moved from state where there is nothing to do.<br>
-      if (!AM)<br>
+      // InnerAM is cleared in a moved from state where there is nothing to do.<br>
+      if (!InnerAM)<br>
         return;<br>
<br>
       // Clear out the analysis manager if we're being destroyed -- it means we<br>
       // didn't even see an invalidate call when we got invalidated.<br>
-      AM->clear();<br>
+      InnerAM->clear();<br>
     }<br>
<br>
     /// \brief Accessor for the analysis manager.<br>
-    AnalysisManagerT &getManager() { return *AM; }<br>
+    AnalysisManagerT &getManager() { return *InnerAM; }<br>
<br>
-    /// \brief Handler for invalidation of the module.<br>
+    /// \brief Handler for invalidation of the outer IR unit.<br>
     ///<br>
     /// If this analysis itself is preserved, then we assume that the set of \c<br>
-    /// Function objects in the \c Module hasn't changed and thus we don't need<br>
-    /// to invalidate *all* cached data associated with a \c Function* in the \c<br>
-    /// FunctionAnalysisManager.<br>
+    /// IR units that the inner analysis manager controls hasn't changed and<br>
+    /// thus we don't need to invalidate *all* cached data associated with any<br>
+    /// \c IRUnitT* in the \c AnalysisManagerT.<br>
     ///<br>
     /// Regardless of whether this analysis is marked as preserved, all of the<br>
-    /// analyses in the \c FunctionAnalysisManager are potentially invalidated<br>
-    /// based on the set of preserved analyses.<br>
+    /// analyses in the \c AnalysisManagerT are potentially invalidated (for<br>
+    /// the relevant inner set of their IR units) based on the set of preserved<br>
+    /// analyses.<br>
+    ///<br>
+    /// Because this needs to understand the mapping from one IR unit to an<br>
+    /// inner IR unit, this method isn't defined in the primary template.<br>
+    /// Instead, each specialization of this template will need to provide an<br>
+    /// explicit specialization of this method to handle that particular pair<br>
+    /// of IR unit and inner AnalysisManagerT.<br>
     bool invalidate(<br>
         IRUnitT &IR, const PreservedAnalyses &PA,<br>
-        typename AnalysisManager<IRUnitT, ExtraArgTs...>::Invalidator &) {<br>
-      // If this proxy isn't marked as preserved, then we can't even invalidate<br>
-      // individual function analyses, there may be an invalid set of Function<br>
-      // objects in the cache making it impossible to incrementally preserve<br>
-      // them. Just clear the entire manager.<br>
-      if (!PA.preserved(<wbr>InnerAnalysisManagerProxy::ID(<wbr>)))<br>
-        AM->clear();<br>
-<br>
-      // Return false to indicate that this result is still a valid proxy.<br>
-      return false;<br>
-    }<br>
+        typename AnalysisManager<IRUnitT, ExtraArgTs...>::Invalidator &Inv);<br>
<br>
   private:<br>
-    AnalysisManagerT *AM;<br>
+    AnalysisManagerT *InnerAM;<br>
   };<br>
<br>
-  explicit InnerAnalysisManagerProxy(<wbr>AnalysisManagerT &AM) : AM(&AM) {}<br>
+  explicit InnerAnalysisManagerProxy(<wbr>AnalysisManagerT &InnerAM)<br>
+      : InnerAM(&InnerAM) {}<br>
<br>
   /// \brief Run the analysis pass and create our proxy result object.<br>
   ///<br>
@@ -817,9 +815,9 @@ public:<br>
   /// In debug builds, it will also assert that the analysis manager is empty<br>
   /// as no queries should arrive at the function analysis manager prior to<br>
   /// this analysis being requested.<br>
-  Result run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &,<br>
+  Result run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,<br>
              ExtraArgTs...) {<br>
-    return Result(*AM);<br>
+    return Result(*InnerAM);<br>
   }<br>
<br>
 private:<br>
@@ -827,19 +825,29 @@ private:<br>
       InnerAnalysisManagerProxy<<wbr>AnalysisManagerT, IRUnitT>>;<br>
   static AnalysisKey Key;<br>
<br>
-  AnalysisManagerT *AM;<br>
+  AnalysisManagerT *InnerAM;<br>
 };<br>
<br>
 template <typename AnalysisManagerT, typename IRUnitT, typename... ExtraArgTs><br>
 AnalysisKey<br>
     InnerAnalysisManagerProxy<<wbr>AnalysisManagerT, IRUnitT, ExtraArgTs...>::Key;<br>
<br>
-extern template class InnerAnalysisManagerProxy<<wbr>FunctionAnalysisManager,<br>
-                                                Module>;<br>
 /// Provide the \c FunctionAnalysisManager to \c Module proxy.<br>
 typedef InnerAnalysisManagerProxy<<wbr>FunctionAnalysisManager, Module><br>
     FunctionAnalysisManagerModuleP<wbr>roxy;<br>
<br>
+/// Specialization of the invalidate method for the \c<br>
+/// FunctionAnalysisManagerModuleP<wbr>roxy's result.<br>
+template <><br>
+bool FunctionAnalysisManagerModuleP<wbr>roxy::Result::invalidate(<br>
+    Module &M, const PreservedAnalyses &PA,<br>
+    ModuleAnalysisManager::<wbr>Invalidator &Inv);<br>
+<br>
+// Ensure the \c FunctionAnalysisManagerModuleP<wbr>roxy is provided as an extern<br>
+// template.<br>
+extern template class InnerAnalysisManagerProxy<<wbr>FunctionAnalysisManager,<br>
+                                                Module>;<br>
+<br>
 /// \brief A function analysis which acts as a proxy for a module analysis<br>
 /// manager.<br>
 ///<br>
<br>
Modified: llvm/trunk/lib/Analysis/<wbr>CGSCCPassManager.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CGSCCPassManager.cpp?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/<wbr>Analysis/CGSCCPassManager.cpp?<wbr>rev=289317&r1=289316&r2=<wbr>289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Analysis/<wbr>CGSCCPassManager.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/<wbr>CGSCCPassManager.cpp Sat Dec 10 00:34:44 2016<br>
@@ -13,6 +13,8 @@<br>
<br>
 using namespace llvm;<br>
<br>
+// Explicit template instantiations and specialization defininitions for core<br>
+// template typedefs.<br>
 namespace llvm {<br>
<br>
 // Explicit instantiations for the core proxy templates.<br>
@@ -22,9 +24,9 @@ template class PassManager<LazyCallGraph<br>
                            LazyCallGraph &, CGSCCUpdateResult &>;<br>
 template class InnerAnalysisManagerProxy<<wbr>CGSCCAnalysisManager, Module>;<br>
 template class OuterAnalysisManagerProxy<<wbr>ModuleAnalysisManager,<br>
-                                         LazyCallGraph::SCC>;<br>
+                                         LazyCallGraph::SCC, LazyCallGraph &>;<br>
 template class InnerAnalysisManagerProxy<<wbr>FunctionAnalysisManager,<br>
-                                         LazyCallGraph::SCC>;<br>
+                                         LazyCallGraph::SCC, LazyCallGraph &>;<br>
 template class OuterAnalysisManagerProxy<<wbr>CGSCCAnalysisManager, Function>;<br>
<br>
 /// Explicitly specialize the pass manager run method to handle call graph<br>
@@ -84,6 +86,87 @@ PassManager<LazyCallGraph::<wbr>SCC, CGSCCAna<br>
   return PA;<br>
 }<br>
<br>
+bool CGSCCAnalysisManagerModuleProx<wbr>y::Result::invalidate(<br>
+    Module &M, const PreservedAnalyses &PA,<br>
+    ModuleAnalysisManager::<wbr>Invalidator &Inv) {<br>
+  // If this proxy or the call graph is going to be invalidated, we also need<br>
+  // to clear all the keys coming from that analysis.<br>
+  //<br>
+  // We also directly invalidate the FAM's module proxy if necessary, and if<br>
+  // that proxy isn't preserved we can't preserve this proxy either. We rely on<br>
+  // it to handle module -> function analysis invalidation in the face of<br>
+  // structural changes and so if it's unavailable we conservatively clear the<br>
+  // entire SCC layer as well rather than trying to do invaliadtion ourselves.<br>
+  if (!PA.preserved<<wbr>CGSCCAnalysisManagerModuleProx<wbr>y>() ||<br>
+      Inv.invalidate<<wbr>LazyCallGraphAnalysis>(M, PA) ||<br>
+      Inv.invalidate<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>(M, PA)) {<br>
+    InnerAM->clear();<br>
+<br>
+    // And the proxy itself should be marked as invalid so that we can observe<br>
+    // the new call graph. This isn't strictly necessary because we cheat<br>
+    // above, but is still useful.<br>
+    return true;<br>
+  }<br>
+<br>
+  // Ok, we have a graph, so we can propagate the invalidation down into it.<br>
+  for (auto &RC : G->postorder_ref_sccs())<br>
+    for (auto &C : RC)<br>
+      InnerAM->invalidate(C, PA);<br>
+<br>
+  // Return false to indicate that this result is still a valid proxy.<br>
+  return false;<br>
+}<br>
+<br>
+template <><br>
+<wbr>CGSCCAnalysisManagerModuleProx<wbr>y::Result<br>
+<wbr>CGSCCAnalysisManagerModuleProx<wbr>y::run(Module &M, ModuleAnalysisManager &AM) {<br>
+  // Force the Function analysis manager to also be available so that it can<br>
+  // be accessed in an SCC analysis and proxied onward to function passes.<br>
+  // FIXME: It is pretty awkward to just drop the result here and assert that<br>
+  // we can find it again later.<br>
+  (void)AM.getResult<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>(M);<br>
+<br>
+  return Result(*InnerAM, AM.getResult<<wbr>LazyCallGraphAnalysis>(M));<br>
+}<br>
+<br>
+AnalysisKey FunctionAnalysisManagerCGSCCPr<wbr>oxy::Key;<br>
+<br>
+<wbr>FunctionAnalysisManagerCGSCCPr<wbr>oxy::Result<br>
+<wbr>FunctionAnalysisManagerCGSCCPr<wbr>oxy::run(LazyCallGraph::SCC &C,<br>
+                                       CGSCCAnalysisManager &AM,<br>
+                                       LazyCallGraph &CG) {<br>
+  // Collect the FunctionAnalysisManager from the Module layer and use that to<br>
+  // build the proxy result.<br>
+  //<br>
+  // This allows us to rely on the FunctionAnalysisMangaerModuleP<wbr>roxy to<br>
+  // invalidate the function analyses.<br>
+  auto &MAM = AM.getResult<<wbr>ModuleAnalysisManagerCGSCCProx<wbr>y>(C, CG).getManager();<br>
+  Module &M = *C.begin()->getFunction().<wbr>getParent();<br>
+  auto *FAMProxy = MAM.getCachedResult<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>(M);<br>
+  assert(FAMProxy && "The CGSCC pass manager requires that the FAM module "<br>
+                     "proxy is run on the module prior to entering the CGSCC "<br>
+                     "walk.");<br>
+<br>
+  // Note that we special-case invalidation handling of this proxy in the CGSCC<br>
+  // analysis manager's Module proxy. This avoids the need to do anything<br>
+  // special here to recompute all of this if ever the FAM's module proxy goes<br>
+  // away.<br>
+  return Result(FAMProxy->getManager())<wbr>;<br>
+}<br>
+<br>
+bool FunctionAnalysisManagerCGSCCPr<wbr>oxy::Result::invalidate(<br>
+    LazyCallGraph::SCC &C, const PreservedAnalyses &PA,<br>
+    CGSCCAnalysisManager::<wbr>Invalidator &Inv) {<br>
+  for (LazyCallGraph::Node &N : C)<br>
+    FAM->invalidate(N.getFunction(<wbr>), PA);<br>
+<br>
+  // This proxy doesn't need to handle invalidation itself. Instead, the<br>
+  // module-level CGSCC proxy handles it above by ensuring that if the<br>
+  // module-level FAM proxy becomes invalid the entire SCC layer, which<br>
+  // includes this proxy, is cleared.<br>
+  return false;<br>
+}<br>
+<br>
 } // End llvm namespace<br>
<br>
 namespace {<br>
<br>
Modified: llvm/trunk/lib/Analysis/<wbr>LoopPassManager.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopPassManager.cpp?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/<wbr>Analysis/LoopPassManager.cpp?<wbr>rev=289317&r1=289316&r2=<wbr>289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Analysis/<wbr>LoopPassManager.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/<wbr>LoopPassManager.cpp Sat Dec 10 00:34:44 2016<br>
@@ -17,12 +17,30 @@<br>
<br>
 using namespace llvm;<br>
<br>
-// Explicit instantiations for core typedef'ed templates.<br>
+// Explicit template instantiations and specialization defininitions for core<br>
+// template typedefs.<br>
 namespace llvm {<br>
 template class PassManager<Loop>;<br>
 template class AnalysisManager<Loop>;<br>
 template class InnerAnalysisManagerProxy<<wbr>LoopAnalysisManager, Function>;<br>
 template class OuterAnalysisManagerProxy<<wbr>FunctionAnalysisManager, Loop>;<br>
+<br>
+template <><br>
+bool LoopAnalysisManagerFunctionPro<wbr>xy::Result::invalidate(<br>
+    Function &F, const PreservedAnalyses &PA,<br>
+    FunctionAnalysisManager::<wbr>Invalidator &Inv) {<br>
+  // If this proxy isn't marked as preserved, the set of Function objects in<br>
+  // the module may have changed. We therefore can't call<br>
+  // InnerAM->invalidate(), because any pointers to Functions it has may be<br>
+  // stale.<br>
+  if (!PA.preserved(<wbr>LoopAnalysisManagerFunctionPro<wbr>xy::ID()))<br>
+    InnerAM->clear();<br>
+<br>
+  // FIXME: Proper suppor for invalidation isn't yet implemented for the LPM.<br>
+<br>
+  // Return false to indicate that this result is still a valid proxy.<br>
+  return false;<br>
+}<br>
 }<br>
<br>
 PreservedAnalyses llvm::<wbr>getLoopPassPreservedAnalyses() {<br>
<br>
Modified: llvm/trunk/lib/IR/PassManager.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/IR/<wbr>PassManager.cpp?rev=289317&r1=<wbr>289316&r2=289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/IR/PassManager.<wbr>cpp (original)<br>
+++ llvm/trunk/lib/IR/PassManager.<wbr>cpp Sat Dec 10 00:34:44 2016<br>
@@ -13,7 +13,8 @@<br>
<br>
 using namespace llvm;<br>
<br>
-// Explicit template instantiations for core template typedefs.<br>
+// Explicit template instantiations and specialization defininitions for core<br>
+// template typedefs.<br>
 namespace llvm {<br>
 template class AllAnalysesOn<Module>;<br>
 template class AllAnalysesOn<Function>;<br>
@@ -23,6 +24,31 @@ template class AnalysisManager<Module>;<br>
 template class AnalysisManager<Function>;<br>
 template class InnerAnalysisManagerProxy<<wbr>FunctionAnalysisManager, Module>;<br>
 template class OuterAnalysisManagerProxy<<wbr>ModuleAnalysisManager, Function>;<br>
+<br>
+template <><br>
+bool FunctionAnalysisManagerModuleP<wbr>roxy::Result::invalidate(<br>
+    Module &M, const PreservedAnalyses &PA,<br>
+    ModuleAnalysisManager::<wbr>Invalidator &Inv) {<br>
+  // If this proxy isn't marked as preserved, then even if the result remains<br>
+  // valid, the key itself may no longer be valid, so we clear everything.<br>
+  //<br>
+  // Note that in order to preserve this proxy, a module pass must ensure that<br>
+  // the FAM has been completely updated to handle the deletion of functions.<br>
+  // Specifically, any FAM-cached results for those functions need to have been<br>
+  // forcibly cleared. When preserved, this proxy will only invalidate results<br>
+  // cached on functions *still in the module* at the end of the module pass.<br>
+  if (!PA.preserved(<wbr>FunctionAnalysisManagerModuleP<wbr>roxy::ID())) {<br>
+    InnerAM->clear();<br>
+    return true;<br>
+  }<br>
+<br>
+  // Otherwise propagate the invalidation event to all the remaining IR units.<br>
+  for (Function &F : M)<br>
+    InnerAM->invalidate(F, PA);<br>
+<br>
+  // Return false to indicate that this result is still a valid proxy.<br>
+  return false;<br>
+}<br>
 }<br>
<br>
 AnalysisKey PreservedAnalyses::<wbr>AllAnalysesKey;<br>
<br>
Modified: llvm/trunk/lib/Passes/<wbr>PassBuilder.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassBuilder.cpp?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/Passes/<wbr>PassBuilder.cpp?rev=289317&r1=<wbr>289316&r2=289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Passes/<wbr>PassBuilder.cpp (original)<br>
+++ llvm/trunk/lib/Passes/<wbr>PassBuilder.cpp Sat Dec 10 00:34:44 2016<br>
@@ -769,7 +769,6 @@ void PassBuilder::<wbr>crossRegisterProxies(L<br>
                                        ModuleAnalysisManager &MAM) {<br>
   MAM.registerPass([&] { return FunctionAnalysisManagerModuleP<wbr>roxy(FAM); });<br>
   MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProx<wbr>y(CGAM); });<br>
-  CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCPr<wbr>oxy(FAM); });<br>
   CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProx<wbr>y(MAM); });<br>
   FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionPr<wbr>oxy(CGAM); });<br>
   FAM.registerPass([&] { return ModuleAnalysisManagerFunctionP<wbr>roxy(MAM); });<br>
<br>
Modified: llvm/trunk/lib/Passes/<wbr>PassRegistry.def<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassRegistry.def?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/Passes/<wbr>PassRegistry.def?rev=289317&<wbr>r1=289316&r2=289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Passes/<wbr>PassRegistry.def (original)<br>
+++ llvm/trunk/lib/Passes/<wbr>PassRegistry.def Sat Dec 10 00:34:44 2016<br>
@@ -79,6 +79,7 @@ MODULE_PASS("verify", VerifierPass())<br>
 #define CGSCC_ANALYSIS(NAME, CREATE_PASS)<br>
 #endif<br>
 CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())<br>
+CGSCC_ANALYSIS("fam-proxy", FunctionAnalysisManagerCGSCCPr<wbr>oxy())<br>
 #undef CGSCC_ANALYSIS<br>
<br>
 #ifndef CGSCC_PASS<br>
<br>
Modified: llvm/trunk/test/Other/new-<wbr>pass-manager.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/new-pass-manager.ll?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/test/Other/<wbr>new-pass-manager.ll?rev=<wbr>289317&r1=289316&r2=289317&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/test/Other/new-<wbr>pass-manager.ll (original)<br>
+++ llvm/trunk/test/Other/new-<wbr>pass-manager.ll Sat Dec 10 00:34:44 2016<br>
@@ -20,7 +20,8 @@<br>
 ; RUN:     | FileCheck %s --check-prefix=CHECK-CGSCC-<wbr>PASS<br>
 ; CHECK-CGSCC-PASS: Starting llvm::Module pass manager run<br>
 ; CHECK-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdap<wbr>tor<br>
-; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*<wbr>}}><br>
+; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*<wbr>}}CGSCCAnalysisManager{{.*}}><br>
+; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*<wbr>}}FunctionAnalysisManager{{.*}<wbr>}><br>
 ; CHECK-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis<br>
 ; CHECK-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)]<br>
 ; CHECK-CGSCC-PASS-NEXT: Starting CGSCC pass manager run<br>
@@ -378,7 +379,8 @@<br>
 ; RUN:     | FileCheck %s --check-prefix=CHECK-REPEAT-<wbr>CGSCC-PASS<br>
 ; CHECK-REPEAT-CGSCC-PASS: Starting llvm::Module pass manager run<br>
 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdap<wbr>tor<br>
-; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*<wbr>}}><br>
+; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*<wbr>}}CGSCCAnalysisManager{{.*}}><br>
+; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*<wbr>}}FunctionAnalysisManager{{.*}<wbr>}><br>
 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis<br>
 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)]<br>
 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting CGSCC pass manager run<br>
<br>
Modified: llvm/trunk/unittests/Analysis/<wbr>CGSCCPassManagerTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/CGSCCPassManagerTest.cpp?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/unittests/<wbr>Analysis/CGSCCPassManagerTest.<wbr>cpp?rev=289317&r1=289316&r2=<wbr>289317&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/Analysis/<wbr>CGSCCPassManagerTest.cpp (original)<br>
+++ llvm/trunk/unittests/Analysis/<wbr>CGSCCPassManagerTest.cpp Sat Dec 10 00:34:44 2016<br>
@@ -122,15 +122,19 @@ private:<br>
<br>
 AnalysisKey TestImmutableFunctionAnalysis:<wbr>:Key;<br>
<br>
+struct LambdaModulePass : public PassInfoMixin<<wbr>LambdaModulePass> {<br>
+  template <typename T><br>
+  LambdaModulePass(T &&Arg) : Func(std::forward<T>(Arg)) {}<br>
+<br>
+  PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) {<br>
+    return Func(F, AM);<br>
+  }<br>
+<br>
+  std::function<<wbr>PreservedAnalyses(Module &, ModuleAnalysisManager &)> Func;<br>
+};<br>
+<br>
 struct LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> {<br>
   template <typename T> LambdaSCCPass(T &&Arg) : Func(std::forward<T>(Arg)) {}<br>
-  // We have to explicitly define all the special member functions because MSVC<br>
-  // refuses to generate them.<br>
-  LambdaSCCPass(LambdaSCCPass &&Arg) : Func(std::move(Arg.Func)) {}<br>
-  LambdaSCCPass &operator=(LambdaSCCPass &&RHS) {<br>
-    Func = std::move(RHS.Func);<br>
-    return *this;<br>
-  }<br>
<br>
   PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,<br>
                         LazyCallGraph &CG, CGSCCUpdateResult &UR) {<br>
@@ -143,14 +147,8 @@ struct LambdaSCCPass : public PassInfoMi<br>
 };<br>
<br>
 struct LambdaFunctionPass : public PassInfoMixin<<wbr>LambdaFunctionPass> {<br>
-  template <typename T> LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}<br>
-  // We have to explicitly define all the special member functions because MSVC<br>
-  // refuses to generate them.<br>
-  LambdaFunctionPass(<wbr>LambdaFunctionPass &&Arg) : Func(std::move(Arg.Func)) {}<br>
-  LambdaFunctionPass &operator=(LambdaFunctionPass &&RHS) {<br>
-    Func = std::move(RHS.Func);<br>
-    return *this;<br>
-  }<br>
+  template <typename T><br>
+  LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}<br>
<br>
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {<br>
     return Func(F, AM);<br>
@@ -232,7 +230,7 @@ public:<br>
     MAM.registerPass([&] { return LazyCallGraphAnalysis(); });<br>
     MAM.registerPass([&] { return FunctionAnalysisManagerModuleP<wbr>roxy(FAM); });<br>
     MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProx<wbr>y(CGAM); });<br>
-    CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCPr<wbr>oxy(FAM); });<br>
+    CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCPr<wbr>oxy(); });<br>
     CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProx<wbr>y(MAM); });<br>
     FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionPr<wbr>oxy(CGAM); });<br>
     FAM.registerPass([&] { return ModuleAnalysisManagerFunctionP<wbr>roxy(MAM); });<br>
@@ -257,6 +255,14 @@ TEST_F(CGSCCPassManagerTest, Basic) {<br>
   MPM.addPass(<wbr>RequireAnalysisPass<<wbr>TestModuleAnalysis, Module>());<br>
<br>
   CGSCCPassManager CGPM1(/*DebugLogging*/ true);<br>
+  FunctionPassManager FPM1(/*DebugLogging*/ true);<br>
+  int FunctionPassRunCount1 = 0;<br>
+  FPM1.addPass(<wbr>LambdaFunctionPass([&](<wbr>Function &, FunctionAnalysisManager &) {<br>
+    ++FunctionPassRunCount1;<br>
+    return PreservedAnalyses::none();<br>
+  }));<br>
+  CGPM1.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM1)));<br>
+<br>
   int SCCPassRunCount1 = 0;<br>
   int AnalyzedInstrCount1 = 0;<br>
   int AnalyzedSCCFunctionCount1 = 0;<br>
@@ -289,23 +295,36 @@ TEST_F(CGSCCPassManagerTest, Basic) {<br>
         return PreservedAnalyses::all();<br>
       }));<br>
<br>
-  FunctionPassManager FPM1(/*DebugLogging*/ true);<br>
-  int FunctionPassRunCount1 = 0;<br>
-  FPM1.addPass(<wbr>LambdaFunctionPass([&](<wbr>Function &, FunctionAnalysisManager &) {<br>
-    ++FunctionPassRunCount1;<br>
-    return PreservedAnalyses::all();<br>
+  FunctionPassManager FPM2(/*DebugLogging*/ true);<br>
+  int FunctionPassRunCount2 = 0;<br>
+  FPM2.addPass(<wbr>LambdaFunctionPass([&](<wbr>Function &, FunctionAnalysisManager &) {<br>
+    ++FunctionPassRunCount2;<br>
+    return PreservedAnalyses::none();<br>
   }));<br>
-  CGPM1.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM1)));<br>
+  CGPM1.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM2)));<br>
+<br>
   MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM1)));<br>
<br>
+  FunctionPassManager FPM3(/*DebugLogging*/ true);<br>
+  int FunctionPassRunCount3 = 0;<br>
+  FPM3.addPass(<wbr>LambdaFunctionPass([&](<wbr>Function &, FunctionAnalysisManager &) {<br>
+    ++FunctionPassRunCount3;<br>
+    return PreservedAnalyses::none();<br>
+  }));<br>
+  MPM.addPass(<wbr>createModuleToFunctionPassAdap<wbr>tor(std::move(FPM3)));<br>
+<br>
   MPM.run(*M, MAM);<br>
<br>
+  EXPECT_EQ(4, SCCPassRunCount1);<br>
+  EXPECT_EQ(6, FunctionPassRunCount1);<br>
+  EXPECT_EQ(6, FunctionPassRunCount2);<br>
+  EXPECT_EQ(6, FunctionPassRunCount3);<br>
+<br>
   EXPECT_EQ(1, ModuleAnalysisRuns);<br>
   EXPECT_EQ(4, SCCAnalysisRuns);<br>
   EXPECT_EQ(6, FunctionAnalysisRuns);<br>
   EXPECT_EQ(6, ImmutableFunctionAnalysisRuns)<wbr>;<br>
<br>
-  EXPECT_EQ(4, SCCPassRunCount1);<br>
   EXPECT_EQ(14, AnalyzedInstrCount1);<br>
   EXPECT_EQ(6, AnalyzedSCCFunctionCount1);<br>
   EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);<br>
@@ -473,4 +492,332 @@ TEST_F(CGSCCPassManagerTest, TestFunctio<br>
   EXPECT_FALSE(<wbr>FoundModuleAnalysis3);<br>
 }<br>
<br>
+// Test that a Module pass which fails to preserve an SCC analysis in fact<br>
+// invalidates that analysis.<br>
+TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAn<wbr>alysis) {<br>
+  int SCCAnalysisRuns = 0;<br>
+  CGAM.registerPass([&] { return TestSCCAnalysis(<wbr>SCCAnalysisRuns); });<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  CGSCCPassManager CGPM1(/*DebugLogging*/ true);<br>
+  CGPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestSCCAnalysis, LazyCallGraph::SCC,<br>
+                                    CGSCCAnalysisManager, LazyCallGraph &,<br>
+                                    CGSCCUpdateResult &>());<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM1)));<br>
+<br>
+  // Now run a module pass that preserves the LazyCallGraph and the proxy but<br>
+  // not the SCC analysis.<br>
+  MPM.addPass(LambdaModulePass([<wbr>&](Module &M, ModuleAnalysisManager &) {<br>
+    PreservedAnalyses PA;<br>
+    PA.preserve<<wbr>LazyCallGraphAnalysis>();<br>
+    PA.preserve<<wbr>CGSCCAnalysisManagerModuleProx<wbr>y>();<br>
+    PA.preserve<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>();<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again. This<br>
+  // will trigger re-running it.<br>
+  CGSCCPassManager CGPM2(/*DebugLogging*/ true);<br>
+  CGPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestSCCAnalysis, LazyCallGraph::SCC,<br>
+                                    CGSCCAnalysisManager, LazyCallGraph &,<br>
+                                    CGSCCUpdateResult &>());<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM2)));<br>
+<br>
+  MPM.run(*M, MAM);<br>
+  // Two runs and four SCCs.<br>
+  EXPECT_EQ(2 * 4, SCCAnalysisRuns);<br>
+}<br>
+<br>
+// Check that marking the SCC analysis preserved is sufficient to avoid<br>
+// invaliadtion. This should only run the analysis once for each SCC.<br>
+TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveSCCAn<wbr>alysis) {<br>
+  int SCCAnalysisRuns = 0;<br>
+  CGAM.registerPass([&] { return TestSCCAnalysis(<wbr>SCCAnalysisRuns); });<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  CGSCCPassManager CGPM1(/*DebugLogging*/ true);<br>
+  CGPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestSCCAnalysis, LazyCallGraph::SCC,<br>
+                                    CGSCCAnalysisManager, LazyCallGraph &,<br>
+                                    CGSCCUpdateResult &>());<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM1)));<br>
+<br>
+  // Now run a module pass that preserves each of the necessary components<br>
+  // (but not everything).<br>
+  MPM.addPass(LambdaModulePass([<wbr>&](Module &M, ModuleAnalysisManager &) {<br>
+    PreservedAnalyses PA;<br>
+    PA.preserve<<wbr>LazyCallGraphAnalysis>();<br>
+    PA.preserve<<wbr>CGSCCAnalysisManagerModuleProx<wbr>y>();<br>
+    PA.preserve<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>();<br>
+    PA.preserve<TestSCCAnalysis>()<wbr>;<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again but find<br>
+  // it in the cache.<br>
+  CGSCCPassManager CGPM2(/*DebugLogging*/ true);<br>
+  CGPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestSCCAnalysis, LazyCallGraph::SCC,<br>
+                                    CGSCCAnalysisManager, LazyCallGraph &,<br>
+                                    CGSCCUpdateResult &>());<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM2)));<br>
+<br>
+  MPM.run(*M, MAM);<br>
+  // Four SCCs<br>
+  EXPECT_EQ(4, SCCAnalysisRuns);<br>
+}<br>
+<br>
+// Check that even when the analysis is preserved, if the SCC information isn't<br>
+// we still nuke things because the SCC keys could change.<br>
+TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAn<wbr>alysisOnCGChange) {<br>
+  int SCCAnalysisRuns = 0;<br>
+  CGAM.registerPass([&] { return TestSCCAnalysis(<wbr>SCCAnalysisRuns); });<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  CGSCCPassManager CGPM1(/*DebugLogging*/ true);<br>
+  CGPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestSCCAnalysis, LazyCallGraph::SCC,<br>
+                                    CGSCCAnalysisManager, LazyCallGraph &,<br>
+                                    CGSCCUpdateResult &>());<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM1)));<br>
+<br>
+  // Now run a module pass that preserves the analysis but not the call<br>
+  // graph or proxy.<br>
+  MPM.addPass(LambdaModulePass([<wbr>&](Module &M, ModuleAnalysisManager &) {<br>
+    PreservedAnalyses PA;<br>
+    PA.preserve<TestSCCAnalysis>()<wbr>;<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again.<br>
+  CGSCCPassManager CGPM2(/*DebugLogging*/ true);<br>
+  CGPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestSCCAnalysis, LazyCallGraph::SCC,<br>
+                                    CGSCCAnalysisManager, LazyCallGraph &,<br>
+                                    CGSCCUpdateResult &>());<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM2)));<br>
+<br>
+  MPM.run(*M, MAM);<br>
+  // Two runs and four SCCs.<br>
+  EXPECT_EQ(2 * 4, SCCAnalysisRuns);<br>
+}<br>
+<br>
+// Test that an SCC pass which fails to preserve a Function analysis in fact<br>
+// invalidates that analysis.<br>
+TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesFunction<wbr>Analysis) {<br>
+  int FunctionAnalysisRuns = 0;<br>
+  FAM.registerPass([&] { return TestFunctionAnalysis(<wbr>FunctionAnalysisRuns); });<br>
+<br>
+  // Create a very simple module with a single function and SCC to make testing<br>
+  // these issues much easier.<br>
+  std::unique_ptr<Module> M = parseIR("declare void @g()\n"<br>
+                                      "declare void @h()\n"<br>
+                                      "define void @f() {\n"<br>
+                                      "entry:\n"<br>
+                                      "  call void @g()\n"<br>
+                                      "  call void @h()\n"<br>
+                                      "  ret void\n"<br>
+                                      "}\n");<br>
+<br>
+  CGSCCPassManager CGPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  FunctionPassManager FPM1(/*DebugLogging*/ true);<br>
+  FPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGPM.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM1)));<br>
+<br>
+  // Now run a module pass that preserves the LazyCallGraph and proxy but not<br>
+  // the SCC analysis.<br>
+  CGPM.addPass(LambdaSCCPass([&]<wbr>(LazyCallGraph::SCC &C, CGSCCAnalysisManager &,<br>
+                                 LazyCallGraph &, CGSCCUpdateResult &) {<br>
+    PreservedAnalyses PA;<br>
+    PA.preserve<<wbr>LazyCallGraphAnalysis>();<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again. This<br>
+  // will trigger re-running it.<br>
+  FunctionPassManager FPM2(/*DebugLogging*/ true);<br>
+  FPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGPM.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM2)));<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM)));<br>
+  MPM.run(*M, MAM);<br>
+  EXPECT_EQ(2, FunctionAnalysisRuns);<br>
+}<br>
+<br>
+// Check that marking the SCC analysis preserved is sufficient. This should<br>
+// only run the analysis once the SCC.<br>
+TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunction<wbr>Analysis) {<br>
+  int FunctionAnalysisRuns = 0;<br>
+  FAM.registerPass([&] { return TestFunctionAnalysis(<wbr>FunctionAnalysisRuns); });<br>
+<br>
+  // Create a very simple module with a single function and SCC to make testing<br>
+  // these issues much easier.<br>
+  std::unique_ptr<Module> M = parseIR("declare void @g()\n"<br>
+                                      "declare void @h()\n"<br>
+                                      "define void @f() {\n"<br>
+                                      "entry:\n"<br>
+                                      "  call void @g()\n"<br>
+                                      "  call void @h()\n"<br>
+                                      "  ret void\n"<br>
+                                      "}\n");<br>
+<br>
+  CGSCCPassManager CGPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  FunctionPassManager FPM1(/*DebugLogging*/ true);<br>
+  FPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGPM.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM1)));<br>
+<br>
+  // Now run a module pass that preserves each of the necessary components<br>
+  // (but<br>
+  // not everything).<br>
+  CGPM.addPass(LambdaSCCPass([&]<wbr>(LazyCallGraph::SCC &C, CGSCCAnalysisManager &,<br>
+                                 LazyCallGraph &, CGSCCUpdateResult &) {<br>
+    PreservedAnalyses PA;<br>
+    PA.preserve<<wbr>LazyCallGraphAnalysis>();<br>
+    PA.preserve<<wbr>TestFunctionAnalysis>();<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again but find<br>
+  // it in the cache.<br>
+  FunctionPassManager FPM2(/*DebugLogging*/ true);<br>
+  FPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGPM.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM2)));<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM)));<br>
+  MPM.run(*M, MAM);<br>
+  EXPECT_EQ(1, FunctionAnalysisRuns);<br>
+}<br>
+<br>
+// Note that there is no test for invalidating the call graph or other<br>
+// structure with an SCC pass because there is no mechanism to do that from<br>
+// withinsuch a pass. Instead, such a pass has to directly update the call<br>
+// graph structure.<br>
+<br>
+// Test that a madule pass invalidates function analyses when the CGSCC proxies<br>
+// and pass manager.<br>
+TEST_F(CGSCCPassManagerTest,<br>
+       TestModulePassInvalidatesFunct<wbr>ionAnalysisNestedInCGSCC) {<br>
+  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });<br>
+<br>
+  int FunctionAnalysisRuns = 0;<br>
+  FAM.registerPass([&] { return TestFunctionAnalysis(<wbr>FunctionAnalysisRuns); });<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  FunctionPassManager FPM1(/*DebugLogging*/ true);<br>
+  FPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGSCCPassManager CGPM1(/*DebugLogging*/ true);<br>
+  CGPM1.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM1)));<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM1)));<br>
+<br>
+  // Now run a module pass that preserves the LazyCallGraph and proxy but not<br>
+  // the Function analysis.<br>
+  MPM.addPass(LambdaModulePass([<wbr>&](Module &M, ModuleAnalysisManager &) {<br>
+    PreservedAnalyses PA;<br>
+    PA.preserve<<wbr>LazyCallGraphAnalysis>();<br>
+    PA.preserve<<wbr>CGSCCAnalysisManagerModuleProx<wbr>y>();<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again. This<br>
+  // will trigger re-running it.<br>
+  FunctionPassManager FPM2(/*DebugLogging*/ true);<br>
+  FPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGSCCPassManager CGPM2(/*DebugLogging*/ true);<br>
+  CGPM2.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM2)));<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM2)));<br>
+<br>
+  MPM.run(*M, MAM);<br>
+  // Two runs and 6 functions.<br>
+  EXPECT_EQ(2 * 6, FunctionAnalysisRuns);<br>
+}<br>
+<br>
+// Check that by marking the function pass and FAM proxy as preserved, this<br>
+// propagates all the way through.<br>
+TEST_F(CGSCCPassManagerTest,<br>
+       TestModulePassCanPreserveFunct<wbr>ionAnalysisNestedInCGSCC) {<br>
+  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });<br>
+<br>
+  int FunctionAnalysisRuns = 0;<br>
+  FAM.registerPass([&] { return TestFunctionAnalysis(<wbr>FunctionAnalysisRuns); });<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  FunctionPassManager FPM1(/*DebugLogging*/ true);<br>
+  FPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGSCCPassManager CGPM1(/*DebugLogging*/ true);<br>
+  CGPM1.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM1)));<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM1)));<br>
+<br>
+  // Now run a module pass that preserves the LazyCallGraph, the proxy, and<br>
+  // the Function analysis.<br>
+  MPM.addPass(LambdaModulePass([<wbr>&](Module &M, ModuleAnalysisManager &) {<br>
+    PreservedAnalyses PA;<br>
+    PA.preserve<<wbr>LazyCallGraphAnalysis>();<br>
+    PA.preserve<<wbr>CGSCCAnalysisManagerModuleProx<wbr>y>();<br>
+    PA.preserve<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>();<br>
+    PA.preserve<<wbr>TestFunctionAnalysis>();<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again. This<br>
+  // will trigger re-running it.<br>
+  FunctionPassManager FPM2(/*DebugLogging*/ true);<br>
+  FPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGSCCPassManager CGPM2(/*DebugLogging*/ true);<br>
+  CGPM2.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM2)));<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM2)));<br>
+<br>
+  MPM.run(*M, MAM);<br>
+  // One run and 6 functions.<br>
+  EXPECT_EQ(6, FunctionAnalysisRuns);<br>
+}<br>
+<br>
+// Check that if the lazy call graph itself isn't preserved we still manage to<br>
+// invalidate everything.<br>
+TEST_F(CGSCCPassManagerTest,<br>
+       TestModulePassInvalidatesFunct<wbr>ionAnalysisNestedInCGSCCOnCGCh<wbr>ange) {<br>
+  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });<br>
+<br>
+  int FunctionAnalysisRuns = 0;<br>
+  FAM.registerPass([&] { return TestFunctionAnalysis(<wbr>FunctionAnalysisRuns); });<br>
+<br>
+  ModulePassManager MPM(/*DebugLogging*/ true);<br>
+<br>
+  // First force the analysis to be run.<br>
+  FunctionPassManager FPM1(/*DebugLogging*/ true);<br>
+  FPM1.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGSCCPassManager CGPM1(/*DebugLogging*/ true);<br>
+  CGPM1.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM1)));<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM1)));<br>
+<br>
+  // Now run a module pass that preserves the LazyCallGraph but not the<br>
+  // Function analysis.<br>
+  MPM.addPass(LambdaModulePass([<wbr>&](Module &M, ModuleAnalysisManager &) {<br>
+    PreservedAnalyses PA;<br>
+    return PA;<br>
+  }));<br>
+<br>
+  // And now a second CGSCC run which requires the SCC analysis again. This<br>
+  // will trigger re-running it.<br>
+  FunctionPassManager FPM2(/*DebugLogging*/ true);<br>
+  FPM2.addPass(<wbr>RequireAnalysisPass<<wbr>TestFunctionAnalysis, Function>());<br>
+  CGSCCPassManager CGPM2(/*DebugLogging*/ true);<br>
+  CGPM2.addPass(<wbr>createCGSCCToFunctionPassAdapt<wbr>or(std::move(FPM2)));<br>
+  MPM.addPass(<wbr>createModuleToPostOrderCGSCCPa<wbr>ssAdaptor(std::move(CGPM2)));<br>
+<br>
+  MPM.run(*M, MAM);<br>
+  // Two runs and 6 functions.<br>
+  EXPECT_EQ(2 * 6, FunctionAnalysisRuns);<br>
+}<br>
 }<br>
<br>
Modified: llvm/trunk/unittests/IR/<wbr>PassManagerTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/PassManagerTest.cpp?rev=289317&r1=289316&r2=289317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/unittests/<wbr>IR/PassManagerTest.cpp?rev=<wbr>289317&r1=289316&r2=289317&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/IR/<wbr>PassManagerTest.cpp (original)<br>
+++ llvm/trunk/unittests/IR/<wbr>PassManagerTest.cpp Sat Dec 10 00:34:44 2016<br>
@@ -91,19 +91,6 @@ struct TestPreservingModulePass : PassIn<br>
   }<br>
 };<br>
<br>
-struct TestMinPreservingModulePass<br>
-    : PassInfoMixin<<wbr>TestMinPreservingModulePass> {<br>
-  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {<br>
-    PreservedAnalyses PA;<br>
-<br>
-    // Force running an analysis.<br>
-    (void)AM.getResult<<wbr>TestModuleAnalysis>(M);<br>
-<br>
-    PA.preserve<<wbr>FunctionAnalysisManagerModuleP<wbr>roxy>();<br>
-    return PA;<br>
-  }<br>
-};<br>
-<br>
 struct TestFunctionPass : PassInfoMixin<<wbr>TestFunctionPass> {<br>
   TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,<br>
                    int &AnalyzedFunctionCount,<br>
@@ -215,11 +202,11 @@ TEST_F(PassManagerTest, BasicPreservedAn<br>
 }<br>
<br>
 TEST_F(PassManagerTest, Basic) {<br>
-  FunctionAnalysisManager FAM;<br>
+  FunctionAnalysisManager FAM(/*DebugLogging*/ true);<br>
   int FunctionAnalysisRuns = 0;<br>
   FAM.registerPass([&] { return TestFunctionAnalysis(<wbr>FunctionAnalysisRuns); });<br>
<br>
-  ModuleAnalysisManager MAM;<br>
+  ModuleAnalysisManager MAM(/*DebugLogging*/ true);<br>
   int ModuleAnalysisRuns = 0;<br>
   MAM.registerPass([&] { return TestModuleAnalysis(<wbr>ModuleAnalysisRuns); });<br>
   MAM.registerPass([&] { return FunctionAnalysisManagerModuleP<wbr>roxy(FAM); });<br>
@@ -233,11 +220,11 @@ TEST_F(PassManagerTest, Basic) {<br>
   int AnalyzedFunctionCount1 = 0;<br>
   {<br>
     // Pointless scoped copy to test move assignment.<br>
-    ModulePassManager NestedMPM;<br>
+    ModulePassManager NestedMPM(/*DebugLogging*/ true);<br>
     FunctionPassManager FPM;<br>
     {<br>
       // Pointless scope to test move assignment.<br>
-      FunctionPassManager NestedFPM;<br>
+      FunctionPassManager NestedFPM(/*DebugLogging*/ true);<br>
       NestedFPM.addPass(<wbr>TestFunctionPass(<br>
           FunctionPassRunCount1, AnalyzedInstrCount1, AnalyzedFunctionCount1));<br>
       FPM = std::move(NestedFPM);<br>
@@ -255,7 +242,7 @@ TEST_F(PassManagerTest, Basic) {<br>
   int AnalyzedInstrCount2 = 0;<br>
   int AnalyzedFunctionCount2 = 0;<br>
   {<br>
-    FunctionPassManager FPM;<br>
+    FunctionPassManager FPM(/*DebugLogging*/ true);<br>
     FPM.addPass(TestFunctionPass(<wbr>FunctionPassRunCount2, AnalyzedInstrCount2,<br>
                                  AnalyzedFunctionCount2));<br>
     MPM.addPass(<wbr>createModuleToFunctionPassAdap<wbr>tor(std::move(FPM)));<br>
@@ -268,15 +255,16 @@ TEST_F(PassManagerTest, Basic) {<br>
   int AnalyzedInstrCount3 = 0;<br>
   int AnalyzedFunctionCount3 = 0;<br>
   {<br>
-    FunctionPassManager FPM;<br>
+    FunctionPassManager FPM(/*DebugLogging*/ true);<br>
     FPM.addPass(TestFunctionPass(<wbr>FunctionPassRunCount3, AnalyzedInstrCount3,<br>
                                  AnalyzedFunctionCount3));<br>
     FPM.addPass(<wbr>TestInvalidationFunctionPass("<wbr>f"));<br>
     MPM.addPass(<wbr>createModuleToFunctionPassAdap<wbr>tor(std::move(FPM)));<br>
   }<br>
<br>
-  // A fourth function pass manager but with a minimal intervening passes.<br>
-  MPM.addPass(<wbr>TestMinPreservingModulePass())<wbr>;<br>
+  // A fourth function pass manager but with only preserving intervening<br>
+  // passes but triggering the module analysis.<br>
+  MPM.addPass(<wbr>RequireAnalysisPass<<wbr>TestModuleAnalysis, Module>());<br>
   int FunctionPassRunCount4 = 0;<br>
   int AnalyzedInstrCount4 = 0;<br>
   int AnalyzedFunctionCount4 = 0;<br>
@@ -287,12 +275,13 @@ TEST_F(PassManagerTest, Basic) {<br>
     MPM.addPass(<wbr>createModuleToFunctionPassAdap<wbr>tor(std::move(FPM)));<br>
   }<br>
<br>
-  // A fifth function pass manager but which uses only cached results.<br>
+  // A fifth function pass manager which invalidates one function first but<br>
+  // uses only cached results.<br>
   int FunctionPassRunCount5 = 0;<br>
   int AnalyzedInstrCount5 = 0;<br>
   int AnalyzedFunctionCount5 = 0;<br>
   {<br>
-    FunctionPassManager FPM;<br>
+    FunctionPassManager FPM(/*DebugLogging*/ true);<br>
     FPM.addPass(<wbr>TestInvalidationFunctionPass("<wbr>f"));<br>
     FPM.addPass(TestFunctionPass(<wbr>FunctionPassRunCount5, AnalyzedInstrCount5,<br>
                                  AnalyzedFunctionCount5,<br>
@@ -317,16 +306,17 @@ TEST_F(PassManagerTest, Basic) {<br>
   EXPECT_EQ(0, AnalyzedFunctionCount3);<br>
   EXPECT_EQ(3, FunctionPassRunCount4);<br>
   EXPECT_EQ(5, AnalyzedInstrCount4);<br>
-  EXPECT_EQ(0, AnalyzedFunctionCount4);<br>
+  EXPECT_EQ(9, AnalyzedFunctionCount4);<br>
   EXPECT_EQ(3, FunctionPassRunCount5);<br>
   EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.<br>
-  EXPECT_EQ(0, AnalyzedFunctionCount5);<br>
+  EXPECT_EQ(9, AnalyzedFunctionCount5);<br>
<br>
   // Validate the analysis counters:<br>
   //   first run over 3 functions, then module pass invalidates<br>
   //   second run over 3 functions, nothing invalidates<br>
   //   third run over 0 functions, but 1 function invalidated<br>
   //   fourth run over 1 function<br>
+  //   fifth run invalidates 1 function first, but runs over 0 functions<br>
   EXPECT_EQ(7, FunctionAnalysisRuns);<br>
<br>
   EXPECT_EQ(1, ModuleAnalysisRuns);<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>