Index: include/llvm/Analysis/CGSCCPassManager.h =================================================================== --- include/llvm/Analysis/CGSCCPassManager.h +++ include/llvm/Analysis/CGSCCPassManager.h @@ -21,27 +21,29 @@ #ifndef LLVM_ANALYSIS_CGSCCPASSMANAGER_H #define LLVM_ANALYSIS_CGSCCPASSMANAGER_H -#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/ADT/SCCIterator.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/IR/PassManager.h" namespace llvm { -extern template class PassManager; +extern template class PassManager; /// \brief The CGSCC pass manager. /// /// See the documentation for the PassManager template for details. It runs /// a sequency of SCC passes over each SCC that the manager is run over. This /// typedef serves as a convenient way to refer to this construct. -typedef PassManager CGSCCPassManager; +typedef PassManager CGSCCPassManager; -extern template class AnalysisManager; +extern template class AnalysisManager; /// \brief The CGSCC analysis manager. /// /// See the documentation for the AnalysisManager template for detail /// documentation. This typedef serves as a convenient way to refer to this /// construct in the adaptors and proxies used to integrate this into the larger /// pass manager infrastructure. -typedef AnalysisManager CGSCCAnalysisManager; +typedef AnalysisManager CGSCCAnalysisManager; extern template class InnerAnalysisManagerProxy; /// A proxy from a \c CGSCCAnalysisManager to a \c Module. @@ -49,11 +51,13 @@ CGSCCAnalysisManagerModuleProxy; extern template class OuterAnalysisManagerProxy; + CallGraphSCC>; /// A proxy from a \c ModuleAnalysisManager to an \c SCC. -typedef OuterAnalysisManagerProxy +typedef OuterAnalysisManagerProxy ModuleAnalysisManagerCGSCCProxy; +extern cl::opt MaxCGSCCIterations; + /// \brief The core module pass which does a post-order walk of the SCCs and /// runs a CGSCC pass over each one. /// @@ -90,42 +94,56 @@ /// \brief Runs the CGSCC pass across every SCC in the module. PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { - // Setup the CGSCC analysis manager from its proxy. + // This is just a dummy to match the signature of the `run` method. We + // don't currently have any CGSCC analyses. CGSCCAnalysisManager &CGAM = AM.getResult(M).getManager(); - // Get the call graph for this module. - LazyCallGraph &CG = AM.getResult(M); + CallGraph &CG = AM.getResult(M); + + // XXX: no existing CGSCC passes use this. + //bool Changed = doInitialization(CG); + + // Walk the callgraph in bottom-up SCC order. + scc_iterator CGI = scc_begin(&CG); PreservedAnalyses PA = PreservedAnalyses::all(); - for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) { - if (DebugLogging) - dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n"; + std::vector> SCCs; + while (!CGI.isAtEnd()) { + const std::vector &NodeVec = *CGI; + SCCs.emplace_back(llvm::make_unique(CG, &CGI, NodeVec)); + // Copy the current SCC and increment past it so that the pass can hack + // on the SCC if it wants to without invalidating our iterator. + ++CGI; + CallGraphSCC &CurSCC = *SCCs.back(); + for (int i = 0; i < (int)MaxCGSCCIterations; i++) { - for (LazyCallGraph::SCC &C : RC) { - PreservedAnalyses PassPA = Pass.run(C, CGAM); + PreservedAnalyses PassPA = Pass.run(CurSCC, CGAM); - // We know that the CGSCC pass couldn't have invalidated any other - // SCC's analyses (that's the contract of a CGSCC pass), so - // directly handle the CGSCC analysis manager's invalidation here. We - // also update the preserved set of analyses to reflect that invalidated - // analyses are now safe to preserve. - // FIXME: This isn't quite correct. We need to handle the case where the - // pass updated the CG, particularly some child of the current SCC, and - // invalidate its analyses. - PassPA = CGAM.invalidate(C, std::move(PassPA)); + PassPA = CGAM.invalidate(CurSCC, std::move(PassPA)); - // Then intersect the preserved set so that invalidation of module - // analyses will eventually occur when the module pass completes. PA.intersect(std::move(PassPA)); + + if (CurSCC.DevirtualizedCall) { + DEBUG_WITH_TYPE("new-cgscc-pm", { + dbgs() << "Devirtualized call " << i << "\n"; + CurSCC.print(dbgs()); + dbgs() << "\n"; + }); + + // Reset this flag and keep looping. + CurSCC.DevirtualizedCall = false; + continue; + } + break; } } - // By definition we preserve the proxy. This precludes *any* invalidation - // of CGSCC analyses by the proxy, but that's OK because we've taken - // care to invalidate analyses in the CGSCC analysis manager - // incrementally above. - PA.preserve(); + // XXX: The only use of this for CGSCC passes is in the inliner which + // just calls removeDeadFunctions. What to do about this? + // Should we just do a run of globaldce after the CGSCC visitation is + // done? + //Changed |= doFinalization(CG); return PA; } @@ -143,9 +161,9 @@ } extern template class InnerAnalysisManagerProxy; + CallGraphSCC>; /// A proxy from a \c FunctionAnalysisManager to an \c SCC. -typedef InnerAnalysisManagerProxy +typedef InnerAnalysisManagerProxy FunctionAnalysisManagerCGSCCProxy; extern template class OuterAnalysisManagerProxy; @@ -185,30 +203,40 @@ } /// \brief Runs the function pass across every function in the module. - PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) { + PreservedAnalyses run(CallGraphSCC &C, CGSCCAnalysisManager &AM) { // Setup the function analysis manager from its proxy. FunctionAnalysisManager &FAM = AM.getResult(C).getManager(); - if (DebugLogging) - dbgs() << "Running function passes across an SCC: " << C << "\n"; + // XXX: enable after adding ostream operator for CallGraphSCC. + //if (DebugLogging) + // dbgs() << "Running function passes across an SCC: " << C << "\n"; PreservedAnalyses PA = PreservedAnalyses::all(); - for (LazyCallGraph::Node &N : C) { - PreservedAnalyses PassPA = Pass.run(N.getFunction(), FAM); + for (CallGraphNode *N : C) { + Function *F = N->getFunction(); + // XXX: CallGraphSCC may have a null function (for the special "calls + // external" and "called by external") nodes. + // Also, there may be declarations. + if (!F || F->isDeclaration()) + continue; + PreservedAnalyses PassPA = Pass.run(*F, FAM); // We know that the function pass couldn't have invalidated any other // function's analyses (that's the contract of a function pass), so // directly handle the function analysis manager's invalidation here. // Also, update the preserved analyses to reflect that once invalidated // these can again be preserved. - PassPA = FAM.invalidate(N.getFunction(), std::move(PassPA)); + PassPA = FAM.invalidate(*F, std::move(PassPA)); // Then intersect the preserved set so that invalidation of module // analyses will eventually occur when the module pass completes. PA.intersect(std::move(PassPA)); } + C.DevirtualizedCall = RefreshCallGraph(C, C.getCallGraph(), false); + PA.preserve(); + // By definition we preserve the proxy. This precludes *any* invalidation // of function analyses by the proxy, but that's OK because we've taken // care to invalidate analyses in the function analysis manager Index: include/llvm/Analysis/CallGraphSCCPass.h =================================================================== --- include/llvm/Analysis/CallGraphSCCPass.h +++ include/llvm/Analysis/CallGraphSCCPass.h @@ -87,13 +87,22 @@ /// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on. class CallGraphSCC { - const CallGraph &CG; // The call graph for this SCC. + CallGraph &CG; // The call graph for this SCC. void *Context; // The CGPassManager object that is vending this. std::vector Nodes; - public: + + // XXX: hack for CGSCC pass manager to pass stuff back up to the + // ModuleToPostOrderCGSCCPassAdaptor's main visitation loop. + // Also, this should really be called "revisit this SCC". + bool DevirtualizedCall = false; + CallGraphSCC(CallGraph &cg, void *context) : CG(cg), Context(context) {} + // The vector is copied. + CallGraphSCC(CallGraph &cg, void *context, std::vector nodes) + : CG(cg), Context(context), Nodes(nodes) {} + void initialize(CallGraphNode *const *I, CallGraphNode *const *E) { Nodes.assign(I, E); } @@ -109,9 +118,41 @@ iterator begin() const { return Nodes.begin(); } iterator end() const { return Nodes.end(); } - const CallGraph &getCallGraph() { return CG; } + CallGraph &getCallGraph() { return CG; } + StringRef getName() { + if (!Nodes.empty()) + if (CallGraphNode *Node = Nodes.front()) + if (Function *F = Node->getFunction()) + return F->getName(); + return "Null SCC"; + } + void print(raw_ostream &OS) { + if (Nodes.empty() || !Nodes.front() || !Nodes.front()->getFunction()) { + OS << "Null SCC"; + return; + } + for (CallGraphNode *Node : Nodes) { + if (!Node || !Node->getFunction()) { + OS << "null "; + continue; + } + OS << Node->getFunction()->getName() << " "; + } + } }; +/// Scan the functions in the specified CFG and resync the +/// callgraph with the call sites found in it. This is used after +/// FunctionPasses have potentially munged the callgraph, and can be used after +/// CallGraphSCC passes to verify that they correctly updated the callgraph. +/// +/// This function returns true if it devirtualized an existing function call, +/// meaning it turned an indirect call into a direct call. This happens when +/// a function pass like GVN optimizes away stuff feeding the indirect call. +/// This never happens in checking mode. +/// +bool RefreshCallGraph(CallGraphSCC &CurSCC, CallGraph &CG, bool IsCheckingMode); + void initializeDummyCGSCCPassPass(PassRegistry &); /// This pass is required by interprocedural register allocation. It forces Index: include/llvm/Transforms/IPO/ArgumentPromotion.h =================================================================== --- /dev/null +++ include/llvm/Transforms/IPO/ArgumentPromotion.h @@ -0,0 +1,26 @@ +//===-- ArgumentPromotion.h - Promote by-reference arguments --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_ARGUMENTPROMOTION_H +#define LLVM_TRANSFORMS_IPO_ARGUMENTPROMOTION_H + +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct ArgumentPromotionPass : PassInfoMixin { + /// The maximum number of elements to expand, or 0 for unlimited. + unsigned MaxElements = 3; + PreservedAnalyses run(CallGraphSCC &C, CGSCCAnalysisManager &AM); +}; + +} + +#endif // LLVM_TRANSFORMS_IPO_ARGUMENTPROMOTION_H Index: include/llvm/Transforms/IPO/FunctionAttrs.h =================================================================== --- include/llvm/Transforms/IPO/FunctionAttrs.h +++ include/llvm/Transforms/IPO/FunctionAttrs.h @@ -30,7 +30,7 @@ /// attribute. It also discovers function arguments that are not captured by /// the function and marks them with the nocapture attribute. struct PostOrderFunctionAttrsPass : PassInfoMixin { - PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM); + PreservedAnalyses run(CallGraphSCC &C, CGSCCAnalysisManager &AM); }; /// Create a legacy pass manager instance of a pass to compute function attrs Index: include/llvm/Transforms/IPO/InlinerPass.h =================================================================== --- include/llvm/Transforms/IPO/InlinerPass.h +++ include/llvm/Transforms/IPO/InlinerPass.h @@ -17,6 +17,7 @@ #ifndef LLVM_TRANSFORMS_IPO_INLINERPASS_H #define LLVM_TRANSFORMS_IPO_INLINERPASS_H +#include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/InlineCost.h" #include "llvm/Analysis/TargetTransformInfo.h" @@ -80,6 +81,12 @@ ProfileSummaryInfo *PSI; }; +struct InlinerPass : public PassInfoMixin { + int DefaultThreshold = llvm::getDefaultInlineThreshold(); + bool InsertLifetime = true; + PreservedAnalyses run(CallGraphSCC &C, CGSCCAnalysisManager &AM); +}; + } // End llvm namespace #endif Index: include/llvm/Transforms/IPO/PruneEH.h =================================================================== --- /dev/null +++ include/llvm/Transforms/IPO/PruneEH.h @@ -0,0 +1,24 @@ +//===- PruneEH.h - Pass which deletes unused exception handlers -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_PRUNEEH_H +#define LLVM_TRANSFORMS_IPO_PRUNEEH_H + +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct PruneEHPass : PassInfoMixin { + PreservedAnalyses run(CallGraphSCC &C, CGSCCAnalysisManager &AM); +}; + +} + +#endif // LLVM_TRANSFORMS_IPO_PRUNEEH_H Index: lib/Analysis/CGSCCPassManager.cpp =================================================================== --- lib/Analysis/CGSCCPassManager.cpp +++ lib/Analysis/CGSCCPassManager.cpp @@ -13,12 +13,10 @@ // Explicit instantiations for the core proxy templates. namespace llvm { -template class PassManager; -template class AnalysisManager; +template class PassManager; +template class AnalysisManager; template class InnerAnalysisManagerProxy; -template class OuterAnalysisManagerProxy; -template class InnerAnalysisManagerProxy; +template class OuterAnalysisManagerProxy; +template class InnerAnalysisManagerProxy; template class OuterAnalysisManagerProxy; } Index: lib/Analysis/CallGraphSCCPass.cpp =================================================================== --- lib/Analysis/CallGraphSCCPass.cpp +++ lib/Analysis/CallGraphSCCPass.cpp @@ -32,8 +32,10 @@ #define DEBUG_TYPE "cgscc-passmgr" -static cl::opt -MaxIterations("max-cg-scc-iterations", cl::ReallyHidden, cl::init(4)); +namespace llvm { +cl::opt MaxCGSCCIterations("max-cg-scc-iterations", cl::ReallyHidden, + cl::init(4)); +} STATISTIC(MaxSCCIterations, "Maximum CGSCCPassMgr iterations on one SCC"); @@ -100,8 +102,6 @@ bool RunPassOnSCC(Pass *P, CallGraphSCC &CurSCC, CallGraph &CG, bool &CallGraphUpToDate, bool &DevirtualizedCall); - bool RefreshCallGraph(CallGraphSCC &CurSCC, CallGraph &CG, - bool IsCheckingMode); }; } // end anonymous namespace. @@ -164,19 +164,8 @@ return Changed; } - -/// Scan the functions in the specified CFG and resync the -/// callgraph with the call sites found in it. This is used after -/// FunctionPasses have potentially munged the callgraph, and can be used after -/// CallGraphSCC passes to verify that they correctly updated the callgraph. -/// -/// This function returns true if it devirtualized an existing function call, -/// meaning it turned an indirect call into a direct call. This happens when -/// a function pass like GVN optimizes away stuff feeding the indirect call. -/// This never happens in checking mode. -/// -bool CGPassManager::RefreshCallGraph(CallGraphSCC &CurSCC, - CallGraph &CG, bool CheckingMode) { +bool llvm::RefreshCallGraph(CallGraphSCC &CurSCC, CallGraph &CG, + bool CheckingMode) { DenseMap CallSites; DEBUG(dbgs() << "CGSCCPASSMGR: Refreshing SCC with " << CurSCC.size() @@ -473,7 +462,7 @@ << Iteration << '\n'); DevirtualizedCall = false; Changed |= RunAllPassesOnSCC(CurSCC, CG, DevirtualizedCall); - } while (Iteration++ < MaxIterations && DevirtualizedCall); + } while (Iteration++ < MaxCGSCCIterations && DevirtualizedCall); if (DevirtualizedCall) DEBUG(dbgs() << " CGSCCPASSMGR: Stopped iteration after " << Iteration Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -58,6 +58,7 @@ #include "llvm/Support/Regex.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/GCOVProfiler.h" +#include "llvm/Transforms/IPO/ArgumentPromotion.h" #include "llvm/Transforms/IPO/ConstantMerge.h" #include "llvm/Transforms/IPO/CrossDSOCFI.h" #include "llvm/Transforms/IPO/DeadArgumentElimination.h" @@ -68,9 +69,11 @@ #include "llvm/Transforms/IPO/GlobalDCE.h" #include "llvm/Transforms/IPO/GlobalOpt.h" #include "llvm/Transforms/IPO/InferFunctionAttrs.h" +#include "llvm/Transforms/IPO/InlinerPass.h" #include "llvm/Transforms/IPO/Internalize.h" #include "llvm/Transforms/IPO/LowerTypeTests.h" #include "llvm/Transforms/IPO/PartialInlining.h" +#include "llvm/Transforms/IPO/PruneEH.h" #include "llvm/Transforms/IPO/SCCP.h" #include "llvm/Transforms/IPO/StripDeadPrototypes.h" #include "llvm/Transforms/IPO/WholeProgramDevirt.h" @@ -151,8 +154,7 @@ /// \brief No-op CGSCC pass which does nothing. struct NoOpCGSCCPass { - PreservedAnalyses run(LazyCallGraph::SCC &C, - AnalysisManager &) { + PreservedAnalyses run(CallGraphSCC &C, AnalysisManager &) { return PreservedAnalyses::all(); } static StringRef name() { return "NoOpCGSCCPass"; } @@ -165,7 +167,7 @@ public: struct Result {}; - Result run(LazyCallGraph::SCC &, AnalysisManager &) { + Result run(CallGraphSCC &, AnalysisManager &) { return Result(); } static StringRef name() { return "NoOpCGSCCAnalysis"; } Index: lib/Passes/PassRegistry.def =================================================================== --- lib/Passes/PassRegistry.def +++ lib/Passes/PassRegistry.def @@ -81,6 +81,9 @@ #endif CGSCC_PASS("invalidate", InvalidateAllAnalysesPass()) CGSCC_PASS("function-attrs", PostOrderFunctionAttrsPass()) +CGSCC_PASS("inline", InlinerPass()) +CGSCC_PASS("prune-eh", PruneEHPass()) +CGSCC_PASS("argpromotion", ArgumentPromotionPass()) CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass()) #undef CGSCC_PASS Index: lib/Transforms/IPO/ArgumentPromotion.cpp =================================================================== --- lib/Transforms/IPO/ArgumentPromotion.cpp +++ lib/Transforms/IPO/ArgumentPromotion.cpp @@ -29,6 +29,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/IPO/ArgumentPromotion.h" #include "llvm/Transforms/IPO.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/Statistic.h" @@ -1039,3 +1040,19 @@ bool ArgPromotion::doInitialization(CallGraph &CG) { return CallGraphSCCPass::doInitialization(CG); } +PreservedAnalyses ArgumentPromotionPass::run(CallGraphSCC &C, + CGSCCAnalysisManager &AM) { + // XXX: do this to make sure we get the real call graph used by the + // ModuleToPostOrderCGSCCPassAdaptor. Can we do something more "correct" + // here? + CallGraph &CG = C.getCallGraph(); + FunctionAnalysisManager &FAM = + AM.getResult(C).getManager(); + std::function AARGetter = [&]( + Function &F) -> AAResults & { return FAM.getResult(F); }; + + bool Changed = runImpl(C, CG, AARGetter, MaxElements); + if (Changed) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} Index: lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- lib/Transforms/IPO/FunctionAttrs.cpp +++ lib/Transforms/IPO/FunctionAttrs.cpp @@ -1033,62 +1033,6 @@ return setDoesNotRecurse(*F); } -PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C, - CGSCCAnalysisManager &AM) { - FunctionAnalysisManager &FAM = - AM.getResult(C).getManager(); - - // We pass a lambda into functions to wire them up to the analysis manager - // for getting function analyses. - auto AARGetter = [&](Function &F) -> AAResults & { - return FAM.getResult(F); - }; - - // Fill SCCNodes with the elements of the SCC. Also track whether there are - // any external or opt-none nodes that will prevent us from optimizing any - // part of the SCC. - SCCNodeSet SCCNodes; - bool HasUnknownCall = false; - for (LazyCallGraph::Node &N : C) { - Function &F = N.getFunction(); - if (F.hasFnAttribute(Attribute::OptimizeNone)) { - // Treat any function we're trying not to optimize as if it were an - // indirect call and omit it from the node set used below. - HasUnknownCall = true; - continue; - } - // Track whether any functions in this SCC have an unknown call edge. - // Note: if this is ever a performance hit, we can common it with - // subsequent routines which also do scans over the instructions of the - // function. - if (!HasUnknownCall) - for (Instruction &I : instructions(F)) - if (auto CS = CallSite(&I)) - if (!CS.getCalledFunction()) { - HasUnknownCall = true; - break; - } - - SCCNodes.insert(&F); - } - - bool Changed = false; - Changed |= addArgumentReturnedAttrs(SCCNodes); - Changed |= addReadAttrs(SCCNodes, AARGetter); - Changed |= addArgumentAttrs(SCCNodes); - - // If we have no external nodes participating in the SCC, we can deduce some - // more precise attributes as well. - if (!HasUnknownCall) { - Changed |= addNoAliasAttrs(SCCNodes); - Changed |= addNonNullAttrs(SCCNodes); - Changed |= removeConvergentAttrs(SCCNodes); - Changed |= addNoRecurseAttrs(SCCNodes); - } - - return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); -} - namespace { struct PostOrderFunctionAttrsLegacyPass : public CallGraphSCCPass { static char ID; // Pass identification, replacement for typeid @@ -1129,7 +1073,10 @@ bool ExternalNode = false; for (CallGraphNode *I : SCC) { Function *F = I->getFunction(); - if (!F || F->hasFnAttribute(Attribute::OptimizeNone)) { + // XXX: The isDeclaration check here is because in the new PM BasicAA + // uses DomTree which will cause it to crash on declarations. + if (!F || F->isDeclaration() || + F->hasFnAttribute(Attribute::OptimizeNone)) { // External node or function we're trying not to optimize - we both avoid // transform them and avoid leveraging information they provide. ExternalNode = true; @@ -1173,6 +1120,22 @@ return runImpl(SCC, AARGetter); } +PreservedAnalyses PostOrderFunctionAttrsPass::run(CallGraphSCC &C, + CGSCCAnalysisManager &AM) { + FunctionAnalysisManager &FAM = + AM.getResult(C).getManager(); + + // We pass a lambda into functions to wire them up to the analysis manager + // for getting function analyses. + auto AARGetter = [&](Function &F) -> AAResults & { + return FAM.getResult(F); + }; + + return runImpl(C, AARGetter) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} + + namespace { struct ReversePostOrderFunctionAttrsLegacyPass : public ModulePass { static char ID; // Pass identification, replacement for typeid Index: lib/Transforms/IPO/Inliner.cpp =================================================================== --- lib/Transforms/IPO/Inliner.cpp +++ lib/Transforms/IPO/Inliner.cpp @@ -703,3 +703,41 @@ } return true; } + +PreservedAnalyses InlinerPass::run(CallGraphSCC &C, CGSCCAnalysisManager &AM) { + FunctionAnalysisManager &FAM = + AM.getResult(C).getManager(); + const ModuleAnalysisManager &MAM = + AM.getResult(C).getManager(); + + // XXX: do this to make sure we get the real call graph used by the + // ModuleToPostOrderCGSCCPassAdaptor. Can we do something more "correct" + // here? + CallGraph &CG = C.getCallGraph(); + + auto *PSI = MAM.getCachedResult(CG.getModule()); + auto *TLI = MAM.getCachedResult(CG.getModule()); + if (!PSI) + report_fatal_error("ProfileSummaryAnalysis not cached at a higher level!"); + if (!TLI) + report_fatal_error("TargetLbraryAnalysis not computed at a higher level!"); + auto AARGetter = [&](Function &F) -> AAResults & { + return FAM.getResult(F); + }; + std::function GetAssumptionCache = [&]( + Function &F) -> AssumptionCache & { + return FAM.getResult(F); + }; + auto GetInlineCost = [&](CallSite CS) -> InlineCost { + // XXX: Copied from SimpleInliner::getInlineCost + Function *Callee = CS.getCalledFunction(); + TargetTransformInfo &TTI = FAM.getResult(*Callee); + return llvm::getInlineCost(CS, DefaultThreshold, TTI, GetAssumptionCache, + PSI); + }; + bool Changed = inlineCallsImpl(C, CG, GetAssumptionCache, PSI, *TLI, + InsertLifetime, GetInlineCost, AARGetter); + if (Changed) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} Index: lib/Transforms/IPO/PruneEH.cpp =================================================================== --- lib/Transforms/IPO/PruneEH.cpp +++ lib/Transforms/IPO/PruneEH.cpp @@ -14,6 +14,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/IPO/PruneEH.h" #include "llvm/Transforms/IPO.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" @@ -271,3 +272,15 @@ BB->eraseFromParent(); } } + +PreservedAnalyses PruneEHPass::run(CallGraphSCC &C, CGSCCAnalysisManager &AM) { + // XXX: do this to make sure we get the real call graph used by the + // ModuleToPostOrderCGSCCPassAdaptor. Can we do something more "correct" + // here? + CallGraph &CG = C.getCallGraph(); + + bool Changed = runImpl(C, CG); + if (Changed) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} Index: test/Other/new-pass-manager.ll =================================================================== --- test/Other/new-pass-manager.ll +++ test/Other/new-pass-manager.ll @@ -18,15 +18,23 @@ ; RUN: opt -disable-output -disable-verify -debug-pass-manager \ ; RUN: -passes='cgscc(no-op-cgscc)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-CGSCC-PASS -; CHECK-CGSCC-PASS: Starting llvm::Module pass manager run +; CHECK-CGSCC-PASS: Starting llvm::Module pass manager run. ; CHECK-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor ; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> -; CHECK-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis -; CHECK-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)] -; CHECK-CGSCC-PASS-NEXT: Starting llvm::LazyCallGraph::SCC pass manager run -; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass -; CHECK-CGSCC-PASS-NEXT: Finished llvm::LazyCallGraph::SCC pass manager run -; CHECK-CGSCC-PASS-NEXT: Finished llvm::Module pass manager run +; CHECK-CGSCC-PASS-NEXT: Running analysis: CallGraphAnalysis +; CHECK-CGSCC-PASS-NEXT: Starting llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass on +; CHECK-CGSCC-PASS-NEXT: Finished llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Starting llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass on +; CHECK-CGSCC-PASS-NEXT: Finished llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Starting llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass on +; CHECK-CGSCC-PASS-NEXT: Finished llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Starting llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass on +; CHECK-CGSCC-PASS-NEXT: Finished llvm::CallGraphSCC pass manager run. +; CHECK-CGSCC-PASS-NEXT: Finished llvm::Module pass manager run. ; RUN: opt -disable-output -disable-verify -debug-pass-manager \ ; RUN: -passes=no-op-function %s 2>&1 \ @@ -129,7 +137,7 @@ ; CHECK-ANALYSES: Starting llvm::Module pass manager run ; CHECK-ANALYSES: Running pass: RequireAnalysisPass ; CHECK-ANALYSES: Running analysis: NoOpModuleAnalysis -; CHECK-ANALYSES: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-ANALYSES: Starting llvm::CallGraphSCC pass manager run ; CHECK-ANALYSES: Running pass: RequireAnalysisPass ; CHECK-ANALYSES: Running analysis: NoOpCGSCCAnalysis ; CHECK-ANALYSES: Starting llvm::Function pass manager run @@ -168,6 +176,8 @@ ; CHECK-DO-CACHE-CGSCC-ANALYSIS-RESULTS: Running pass: RequireAnalysisPass ; CHECK-DO-CACHE-CGSCC-ANALYSIS-RESULTS: Running analysis: NoOpCGSCCAnalysis ; CHECK-DO-CACHE-CGSCC-ANALYSIS-RESULTS-NOT: Running analysis: NoOpCGSCCAnalysis +; CHECK-DO-CACHE-CGSCC-ANALYSIS-RESULTS: Running pass: RequireAnalysisPass +; CHECK-DO-CACHE-CGSCC-ANALYSIS-RESULTS: Running pass: RequireAnalysisPass ; RUN: opt -disable-output -debug-pass-manager \ ; RUN: -passes='cgscc(require,invalidate,require)' %s 2>&1 \ @@ -235,7 +245,7 @@ ; CHECK-INVALIDATE-ALL-CG: Starting llvm::Module pass manager run ; CHECK-INVALIDATE-ALL-CG: Running pass: RequireAnalysisPass ; CHECK-INVALIDATE-ALL-CG-NOT: Running analysis: NoOpModuleAnalysis -; CHECK-INVALIDATE-ALL-CG: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-INVALIDATE-ALL-CG: Starting llvm::CallGraphSCC pass manager run ; CHECK-INVALIDATE-ALL-CG: Running pass: RequireAnalysisPass ; CHECK-INVALIDATE-ALL-CG: Running analysis: NoOpCGSCCAnalysis ; CHECK-INVALIDATE-ALL-CG: Starting llvm::Function pass manager run @@ -253,7 +263,7 @@ ; CHECK-INVALIDATE-ALL-CG: Invalidating analysis: NoOpCGSCCAnalysis ; CHECK-INVALIDATE-ALL-CG: Running pass: RequireAnalysisPass ; CHECK-INVALIDATE-ALL-CG: Running analysis: NoOpCGSCCAnalysis -; CHECK-INVALIDATE-ALL-CG: Finished llvm::LazyCallGraph::SCC pass manager run +; CHECK-INVALIDATE-ALL-CG: Finished llvm::CallGraphSCC pass manager run ; CHECK-INVALIDATE-ALL-CG: Invalidating all non-preserved analyses ; CHECK-INVALIDATE-ALL-CG-NOT: Invalidating analysis: NoOpCGSCCAnalysis ; CHECK-INVALIDATE-ALL-CG: Invalidating all non-preserved analyses Index: test/Other/pass-pipeline-parsing.ll =================================================================== --- test/Other/pass-pipeline-parsing.ll +++ test/Other/pass-pipeline-parsing.ll @@ -106,10 +106,10 @@ ; RUN: | FileCheck %s --check-prefix=CHECK-TWO-NOOP-CG ; CHECK-TWO-NOOP-CG: Starting llvm::Module pass manager run ; CHECK-TWO-NOOP-CG: Running pass: ModuleToPostOrderCGSCCPassAdaptor -; CHECK-TWO-NOOP-CG: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-TWO-NOOP-CG: Starting llvm::CallGraphSCC pass manager run ; CHECK-TWO-NOOP-CG: Running pass: NoOpCGSCCPass ; CHECK-TWO-NOOP-CG: Running pass: NoOpCGSCCPass -; CHECK-TWO-NOOP-CG: Finished llvm::LazyCallGraph::SCC pass manager run +; CHECK-TWO-NOOP-CG: Finished llvm::CallGraphSCC pass manager run ; CHECK-TWO-NOOP-CG: Finished llvm::Module pass manager run ; RUN: opt -disable-output -debug-pass-manager \ @@ -122,14 +122,14 @@ ; CHECK-NESTED-MP-CG-FP: Running pass: NoOpFunctionPass ; CHECK-NESTED-MP-CG-FP: Finished llvm::Function pass manager run ; CHECK-NESTED-MP-CG-FP: Running pass: ModuleToPostOrderCGSCCPassAdaptor -; CHECK-NESTED-MP-CG-FP: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-NESTED-MP-CG-FP: Starting llvm::CallGraphSCC pass manager run ; CHECK-NESTED-MP-CG-FP: Running pass: NoOpCGSCCPass ; CHECK-NESTED-MP-CG-FP: Running pass: CGSCCToFunctionPassAdaptor ; CHECK-NESTED-MP-CG-FP: Starting llvm::Function pass manager run ; CHECK-NESTED-MP-CG-FP: Running pass: NoOpFunctionPass ; CHECK-NESTED-MP-CG-FP: Finished llvm::Function pass manager run ; CHECK-NESTED-MP-CG-FP: Running pass: NoOpCGSCCPass -; CHECK-NESTED-MP-CG-FP: Finished llvm::LazyCallGraph::SCC pass manager run +; CHECK-NESTED-MP-CG-FP: Finished llvm::CallGraphSCC pass manager run ; CHECK-NESTED-MP-CG-FP: Running pass: ModuleToFunctionPassAdaptor ; CHECK-NESTED-MP-CG-FP: Starting llvm::Function pass manager run ; CHECK-NESTED-MP-CG-FP: Running pass: NoOpFunctionPass Index: test/Transforms/ArgumentPromotion/byval.ll =================================================================== --- test/Transforms/ArgumentPromotion/byval.ll +++ test/Transforms/ArgumentPromotion/byval.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -argpromotion -S | FileCheck %s +; RUN: opt < %s -passes=argpromotion -S | FileCheck %s target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" Index: test/Transforms/Inline/alloca-in-scc.ll =================================================================== --- test/Transforms/Inline/alloca-in-scc.ll +++ test/Transforms/Inline/alloca-in-scc.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -inline | llvm-dis +; RUN: opt < %s -passes='module(require,require,cgscc(inline))' | llvm-dis target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" target triple = "i386-apple-darwin10.0" Index: test/Transforms/PruneEH/2008-06-02-Weak.ll =================================================================== --- test/Transforms/PruneEH/2008-06-02-Weak.ll +++ test/Transforms/PruneEH/2008-06-02-Weak.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -prune-eh -S | not grep nounwind +; RUN: opt < %s -passes=prune-eh -S | not grep nounwind define weak void @f() { entry: Index: test/Transforms/PruneEH/operand-bundles.ll =================================================================== --- test/Transforms/PruneEH/operand-bundles.ll +++ test/Transforms/PruneEH/operand-bundles.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -prune-eh -S | FileCheck %s +; RUN: opt < %s -passes=prune-eh -S | FileCheck %s declare void @nounwind() nounwind Index: test/Transforms/PruneEH/pr23971.ll =================================================================== --- test/Transforms/PruneEH/pr23971.ll +++ test/Transforms/PruneEH/pr23971.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -prune-eh < %s | FileCheck %s +; RUN: opt -S -passes=prune-eh < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" Index: test/Transforms/PruneEH/pr26263.ll =================================================================== --- test/Transforms/PruneEH/pr26263.ll +++ test/Transforms/PruneEH/pr26263.ll @@ -1,4 +1,5 @@ ; RUN: opt -prune-eh -S < %s | FileCheck %s +; RUN: opt -passes=prune-eh -S < %s | FileCheck %s target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" target triple = "i386-pc-windows-msvc" Index: test/Transforms/PruneEH/recursivetest.ll =================================================================== --- test/Transforms/PruneEH/recursivetest.ll +++ test/Transforms/PruneEH/recursivetest.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -prune-eh -S | not grep invoke +; RUN: opt < %s -passes=prune-eh -S | not grep invoke define internal i32 @foo() personality i32 (...)* @__gxx_personality_v0 { invoke i32 @foo( ) Index: test/Transforms/PruneEH/seh-nounwind.ll =================================================================== --- test/Transforms/PruneEH/seh-nounwind.ll +++ test/Transforms/PruneEH/seh-nounwind.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -prune-eh < %s | FileCheck %s +; RUN: opt -S -passes=prune-eh < %s | FileCheck %s ; Don't remove invokes of nounwind functions if the personality handles async ; exceptions. The @div function in this test can fault, even though it can't Index: test/Transforms/PruneEH/simplenoreturntest.ll =================================================================== --- test/Transforms/PruneEH/simplenoreturntest.ll +++ test/Transforms/PruneEH/simplenoreturntest.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -prune-eh -S | not grep "ret i32" +; RUN: opt < %s -passes=prune-eh -S | not grep "ret i32" declare void @noreturn() noreturn Index: test/Transforms/PruneEH/simpletest.ll =================================================================== --- test/Transforms/PruneEH/simpletest.ll +++ test/Transforms/PruneEH/simpletest.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -prune-eh -S | not grep invoke +; RUN: opt < %s -passes=prune-eh -S | not grep invoke declare void @nounwind() nounwind Index: unittests/Analysis/CGSCCPassManagerTest.cpp =================================================================== --- unittests/Analysis/CGSCCPassManagerTest.cpp +++ unittests/Analysis/CGSCCPassManagerTest.cpp @@ -59,7 +59,7 @@ TestSCCAnalysis(int &Runs) : Runs(Runs) {} - Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) { + Result run(CallGraphSCC &C, CGSCCAnalysisManager &AM) { ++Runs; return Result(C.size()); } @@ -149,7 +149,7 @@ AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount), OnlyUseCachedResults(OnlyUseCachedResults) {} - PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) { + PreservedAnalyses run(CallGraphSCC &C, CGSCCAnalysisManager &AM) { ++RunCount; const ModuleAnalysisManager &MAM = @@ -158,28 +158,35 @@ AM.getResult(C).getManager(); if (TestModuleAnalysis::Result *TMA = MAM.getCachedResult( - *C.begin()->getFunction().getParent())) + C.getCallGraph().getModule())) AnalyzedModuleFunctionCount += TMA->FunctionCount; if (OnlyUseCachedResults) { // Hack to force the use of the cached interface. if (TestSCCAnalysis::Result *AR = AM.getCachedResult(C)) AnalyzedSCCFunctionCount += AR->FunctionCount; - for (LazyCallGraph::Node &N : C) + for (CallGraphNode *N : C) { + // XXX: The old PM can call on SCC's with null nodes. + if (!N->getFunction()) + continue; if (TestFunctionAnalysis::Result *FAR = - FAM.getCachedResult(N.getFunction())) + FAM.getCachedResult(*N->getFunction())) AnalyzedInstrCount += FAR->InstructionCount; + } } else { // Typical path just runs the analysis as needed. TestSCCAnalysis::Result &AR = AM.getResult(C); AnalyzedSCCFunctionCount += AR.FunctionCount; - for (LazyCallGraph::Node &N : C) { + for (CallGraphNode *N : C) { + // XXX: The old PM can call on SCC's with null nodes. + if (!N->getFunction()) + continue; TestFunctionAnalysis::Result &FAR = - FAM.getResult(N.getFunction()); + FAM.getResult(*N->getFunction()); AnalyzedInstrCount += FAR.InstructionCount; // Just ensure we get the immutable results. - (void)FAM.getResult(N.getFunction()); + (void)FAM.getResult(*N->getFunction()); } } @@ -264,7 +271,7 @@ ModuleAnalysisManager MAM(/*DebugLogging*/ true); int ModuleAnalysisRuns = 0; - MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); + MAM.registerPass([&] { return CallGraphAnalysis(); }); MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); @@ -297,15 +304,18 @@ EXPECT_EQ(1, ModulePassRunCount1); + // XXX: Some of these are 1 larger with CallGraphSCC than with + // LazyCallGraph because CallGraph has an explicit "external caller" SCC. + EXPECT_EQ(1, ModuleAnalysisRuns); - EXPECT_EQ(4, SCCAnalysisRuns); + EXPECT_EQ(5, SCCAnalysisRuns); EXPECT_EQ(6, FunctionAnalysisRuns); EXPECT_EQ(6, ImmutableFunctionAnalysisRuns); - EXPECT_EQ(4, SCCPassRunCount1); + EXPECT_EQ(5, SCCPassRunCount1); EXPECT_EQ(14, AnalyzedInstrCount1); - EXPECT_EQ(6, AnalyzedSCCFunctionCount1); - EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1); + EXPECT_EQ(7, AnalyzedSCCFunctionCount1); + EXPECT_EQ(5 * 6, AnalyzedModuleFunctionCount1); } }