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/Analysis/InlineCost.h =================================================================== --- include/llvm/Analysis/InlineCost.h +++ include/llvm/Analysis/InlineCost.h @@ -15,6 +15,7 @@ #define LLVM_ANALYSIS_INLINECOST_H #include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/AssumptionCache.h" #include #include @@ -110,18 +111,21 @@ /// /// Also note that calling this function *dynamically* computes the cost of /// inlining the callsite. It is an expensive, heavyweight call. -InlineCost getInlineCost(CallSite CS, int DefaultThreshold, - TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI); +InlineCost +getInlineCost(CallSite CS, int DefaultThreshold, TargetTransformInfo &CalleeTTI, + std::function &GetAssumptionCache, + ProfileSummaryInfo *PSI); /// \brief Get an InlineCost with the callee explicitly specified. /// This allows you to calculate the cost of inlining a function via a /// pointer. This behaves exactly as the version with no explicit callee /// parameter in all other respects. // -InlineCost getInlineCost(CallSite CS, Function *Callee, int DefaultThreshold, - TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI); +InlineCost +getInlineCost(CallSite CS, Function *Callee, int DefaultThreshold, + TargetTransformInfo &CalleeTTI, + std::function &GetAssumptionCache, + ProfileSummaryInfo *PSI); int computeThresholdFromOptLevels(unsigned OptLevel, unsigned SizeOptLevel); 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,7 +17,10 @@ #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" namespace llvm { class AssumptionCacheTracker; @@ -73,22 +76,17 @@ // InsertLifetime - Insert @llvm.lifetime intrinsics. bool InsertLifetime; - /// shouldInline - Return true if the inliner should attempt to - /// inline at the given CallSite. - bool shouldInline(CallSite CS); - /// Return true if inlining of CS can block the caller from being - /// inlined which is proved to be more beneficial. \p IC is the - /// estimated inline cost associated with callsite \p CS. - /// \p TotalAltCost will be set to the estimated cost of inlining the caller - /// if \p CS is suppressed for inlining. - bool shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC, - int &TotalAltCost); - protected: AssumptionCacheTracker *ACT; 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: include/llvm/Transforms/Utils/Cloning.h =================================================================== --- include/llvm/Transforms/Utils/Cloning.h +++ include/llvm/Transforms/Utils/Cloning.h @@ -21,6 +21,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/IR/ValueHandle.h" #include "llvm/IR/ValueMap.h" #include "llvm/Transforms/Utils/ValueMapper.h" @@ -176,13 +177,14 @@ class InlineFunctionInfo { public: explicit InlineFunctionInfo(CallGraph *cg = nullptr, - AssumptionCacheTracker *ACT = nullptr) - : CG(cg), ACT(ACT) {} + std::function + *GetAssumptionCache = nullptr) + : CG(cg), GetAssumptionCache(GetAssumptionCache) {} /// CG - If non-null, InlineFunction will update the callgraph to reflect the /// changes it makes. CallGraph *CG; - AssumptionCacheTracker *ACT; + std::function *GetAssumptionCache; /// StaticAllocas - InlineFunction fills this in with all static allocas that /// get copied into the caller. 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/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -75,8 +75,8 @@ /// The TargetTransformInfo available for this compilation. const TargetTransformInfo &TTI; - /// The cache of @llvm.assume intrinsics. - AssumptionCacheTracker *ACT; + /// Getter for the cache of @llvm.assume intrinsics. + std::function &GetAssumptionCache; /// Profile summary information. ProfileSummaryInfo *PSI; @@ -203,20 +203,21 @@ bool visitUnreachableInst(UnreachableInst &I); public: - CallAnalyzer(const TargetTransformInfo &TTI, AssumptionCacheTracker *ACT, + CallAnalyzer(const TargetTransformInfo &TTI, + std::function &GetAssumptionCache, ProfileSummaryInfo *PSI, Function &Callee, int Threshold, CallSite CSArg) - : TTI(TTI), ACT(ACT), PSI(PSI), F(Callee), CandidateCS(CSArg), - Threshold(Threshold), Cost(0), IsCallerRecursive(false), - IsRecursiveCall(false), ExposesReturnsTwice(false), - HasDynamicAlloca(false), ContainsNoDuplicateCall(false), - HasReturn(false), HasIndirectBr(false), HasFrameEscape(false), - AllocatedSize(0), NumInstructions(0), NumVectorInstructions(0), - FiftyPercentVectorBonus(0), TenPercentVectorBonus(0), VectorBonus(0), - NumConstantArgs(0), NumConstantOffsetPtrArgs(0), NumAllocaArgs(0), - NumConstantPtrCmps(0), NumConstantPtrDiffs(0), - NumInstructionsSimplified(0), SROACostSavings(0), - SROACostSavingsLost(0) {} + : TTI(TTI), GetAssumptionCache(GetAssumptionCache), PSI(PSI), F(Callee), + CandidateCS(CSArg), Threshold(Threshold), Cost(0), + IsCallerRecursive(false), IsRecursiveCall(false), + ExposesReturnsTwice(false), HasDynamicAlloca(false), + ContainsNoDuplicateCall(false), HasReturn(false), HasIndirectBr(false), + HasFrameEscape(false), AllocatedSize(0), NumInstructions(0), + NumVectorInstructions(0), FiftyPercentVectorBonus(0), + TenPercentVectorBonus(0), VectorBonus(0), NumConstantArgs(0), + NumConstantOffsetPtrArgs(0), NumAllocaArgs(0), NumConstantPtrCmps(0), + NumConstantPtrDiffs(0), NumInstructionsSimplified(0), + SROACostSavings(0), SROACostSavingsLost(0) {} bool analyzeCall(CallSite CS); @@ -950,8 +951,8 @@ // during devirtualization and so we want to give it a hefty bonus for // inlining, but cap that bonus in the event that inlining wouldn't pan // out. Pretend to inline the function, with a custom threshold. - CallAnalyzer CA(TTI, ACT, PSI, *F, InlineConstants::IndirectCallThreshold, - CS); + CallAnalyzer CA(TTI, GetAssumptionCache, PSI, *F, + InlineConstants::IndirectCallThreshold, CS); if (CA.analyzeCall(CS)) { // We were able to inline the indirect call! Subtract the cost from the // threshold to get the bonus we want to apply, but don't go below zero. @@ -1305,8 +1306,7 @@ // the ephemeral values multiple times (and they're completely determined by // the callee, so this is purely duplicate work). SmallPtrSet EphValues; - CodeMetrics::collectEphemeralValues(&F, &ACT->getAssumptionCache(F), - EphValues); + CodeMetrics::collectEphemeralValues(&F, &GetAssumptionCache(F), EphValues); // The worklist of live basic blocks in the callee *after* inlining. We avoid // adding basic blocks of the callee which can be proven to be dead for this @@ -1437,12 +1437,12 @@ AttributeFuncs::areInlineCompatible(*Caller, *Callee); } -InlineCost llvm::getInlineCost(CallSite CS, int DefaultThreshold, - TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT, - ProfileSummaryInfo *PSI) { +InlineCost llvm::getInlineCost( + CallSite CS, int DefaultThreshold, TargetTransformInfo &CalleeTTI, + std::function &GetAssumptionCache, + ProfileSummaryInfo *PSI) { return getInlineCost(CS, CS.getCalledFunction(), DefaultThreshold, CalleeTTI, - ACT, PSI); + GetAssumptionCache, PSI); } int llvm::computeThresholdFromOptLevels(unsigned OptLevel, @@ -1458,11 +1458,11 @@ int llvm::getDefaultInlineThreshold() { return DefaultInlineThreshold; } -InlineCost llvm::getInlineCost(CallSite CS, Function *Callee, - int DefaultThreshold, - TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT, - ProfileSummaryInfo *PSI) { +InlineCost llvm::getInlineCost( + CallSite CS, Function *Callee, int DefaultThreshold, + TargetTransformInfo &CalleeTTI, + std::function &GetAssumptionCache, + ProfileSummaryInfo *PSI) { // Cannot inline indirect calls. if (!Callee) @@ -1496,7 +1496,7 @@ DEBUG(llvm::dbgs() << " Analyzing call of " << Callee->getName() << "...\n"); - CallAnalyzer CA(CalleeTTI, ACT, PSI, *Callee, DefaultThreshold, CS); + CallAnalyzer CA(CalleeTTI, GetAssumptionCache, PSI, *Callee, DefaultThreshold, CS); bool ShouldInline = CA.analyzeCall(CS); DEBUG(CA.dump()); Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -55,6 +55,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/DeadArgumentElimination.h" #include "llvm/Transforms/IPO/ElimAvailExtern.h" @@ -63,8 +64,10 @@ #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/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" @@ -131,8 +134,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"; } @@ -145,7 +147,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 @@ -78,6 +78,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" @@ -1042,3 +1043,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 @@ -984,61 +984,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 |= 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 @@ -1079,7 +1024,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; @@ -1122,6 +1070,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/InlineSimple.cpp =================================================================== --- lib/Transforms/IPO/InlineSimple.cpp +++ lib/Transforms/IPO/InlineSimple.cpp @@ -61,7 +61,12 @@ InlineCost getInlineCost(CallSite CS) override { Function *Callee = CS.getCalledFunction(); TargetTransformInfo &TTI = TTIWP->getTTI(*Callee); - return llvm::getInlineCost(CS, DefaultThreshold, TTI, ACT, PSI); + std::function GetAssumptionCache = [&]( + Function &F) -> AssumptionCache & { + return ACT->getAssumptionCache(F); + }; + return llvm::getInlineCost(CS, DefaultThreshold, TTI, GetAssumptionCache, + PSI); } bool runOnSCC(CallGraphSCC &SCC) override; Index: lib/Transforms/IPO/Inliner.cpp =================================================================== --- lib/Transforms/IPO/Inliner.cpp +++ lib/Transforms/IPO/Inliner.cpp @@ -75,19 +75,15 @@ /// available from other functions inlined into the caller. If we are able to /// inline this call site we attempt to reuse already available allocas or add /// any new allocas to the set if not possible. -static bool InlineCallIfPossible(Pass &P, CallSite CS, InlineFunctionInfo &IFI, - InlinedArrayAllocasTy &InlinedArrayAllocas, - int InlineHistory, bool InsertLifetime) { +static bool +InlineCallIfPossible(CallSite CS, InlineFunctionInfo &IFI, + InlinedArrayAllocasTy &InlinedArrayAllocas, + int InlineHistory, bool InsertLifetime, + std::function &AARGetter) { Function *Callee = CS.getCalledFunction(); Function *Caller = CS.getCaller(); - // We need to manually construct BasicAA directly in order to disable - // its use of other function analyses. - BasicAAResult BAR(createLegacyPMBasicAAResult(P, *Callee)); - - // Construct our own AA results for this function. We do this manually to - // work around the limitations of the legacy pass manager. - AAResults AAR(createLegacyPMAAResults(P, *Callee, BAR)); + AAResults &AAR = AARGetter(*Callee); // Try to inline the function. Get the list of static allocas that were // inlined. @@ -229,8 +225,15 @@ emitOptimizationRemarkAnalysis(Ctx, DEBUG_TYPE, *Caller, DLoc, Msg); } -bool Inliner::shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC, - int &TotalSecondaryCost) { +/// Return true if inlining of CS can block the caller from being +/// inlined which is proved to be more beneficial. \p IC is the +/// estimated inline cost associated with callsite \p CS. +/// \p TotalAltCost will be set to the estimated cost of inlining the caller +/// if \p CS is suppressed for inlining. +static bool +shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC, + int &TotalSecondaryCost, + std::function &GetInlineCost) { // For now we only handle local or inline functions. if (!Caller->hasLocalLinkage() && !Caller->hasLinkOnceODRLinkage()) @@ -269,7 +272,7 @@ continue; } - InlineCost IC2 = getInlineCost(CS2); + InlineCost IC2 = GetInlineCost(CS2); ++NumCallerCallersAnalyzed; if (!IC2) { callerWillBeRemoved = false; @@ -300,8 +303,9 @@ } /// Return true if the inliner should attempt to inline at the given CallSite. -bool Inliner::shouldInline(CallSite CS) { - InlineCost IC = getInlineCost(CS); +static bool shouldInline(CallSite CS, + std::function GetInlineCost) { + InlineCost IC = GetInlineCost(CS); if (IC.isAlways()) { DEBUG(dbgs() << " Inlining: cost=always" @@ -332,7 +336,7 @@ } int TotalSecondaryCost = 0; - if (shouldBeDeferred(Caller, CS, IC, TotalSecondaryCost)) { + if (shouldBeDeferred(Caller, CS, IC, TotalSecondaryCost, GetInlineCost)) { DEBUG(dbgs() << " NOT Inlining: " << *CS.getInstruction() << " Cost = " << IC.getCost() << ", outer Cost = " << TotalSecondaryCost << '\n'); @@ -370,15 +374,17 @@ bool Inliner::runOnSCC(CallGraphSCC &SCC) { if (skipSCC(SCC)) return false; + return inlineCalls(SCC); } -bool Inliner::inlineCalls(CallGraphSCC &SCC) { - CallGraph &CG = getAnalysis().getCallGraph(); - ACT = &getAnalysis(); - PSI = getAnalysis().getPSI(CG.getModule()); - auto &TLI = getAnalysis().getTLI(); - +static bool +inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG, + std::function GetAssumptionCache, + ProfileSummaryInfo *PSI, TargetLibraryInfo &TLI, + bool InsertLifetime, + std::function GetInlineCost, + std::function AARGetter) { SmallPtrSet SCCFunctions; DEBUG(dbgs() << "Inliner visiting SCC:"); for (CallGraphNode *Node : SCC) { @@ -437,7 +443,7 @@ InlinedArrayAllocasTy InlinedArrayAllocas; - InlineFunctionInfo InlineInfo(&CG, ACT); + InlineFunctionInfo InlineInfo(&CG, &GetAssumptionCache); // Now that we have all of the call sites, loop over them and inline them if // it looks profitable to do so. @@ -486,7 +492,7 @@ // If the policy determines that we should inline this function, // try to do so. - if (!shouldInline(CS)) { + if (!shouldInline(CS, GetInlineCost)) { emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc, Twine(Callee->getName() + " will not be inlined into " + @@ -495,8 +501,8 @@ } // Attempt to inline the function. - if (!InlineCallIfPossible(*this, CS, InlineInfo, InlinedArrayAllocas, - InlineHistoryID, InsertLifetime)) { + if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas, + InlineHistoryID, InsertLifetime, AARGetter)) { emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc, Twine(Callee->getName() + " will not be inlined into " + @@ -565,6 +571,29 @@ return Changed; } +bool Inliner::inlineCalls(CallGraphSCC &SCC) { + CallGraph &CG = getAnalysis().getCallGraph(); + ACT = &getAnalysis(); + PSI = getAnalysis().getPSI(CG.getModule()); + auto &TLI = getAnalysis().getTLI(); + // We compute dedicated AA results for each function in the SCC as needed. We + // use a lambda referencing external objects so that they live long enough to + // be queried, but we re-use them each time. + Optional BAR; + Optional AAR; + auto AARGetter = [&](Function &F) -> AAResults & { + BAR.emplace(createLegacyPMBasicAAResult(*this, F)); + AAR.emplace(createLegacyPMAAResults(*this, F, *BAR)); + return *AAR; + }; + auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & { + return ACT->getAssumptionCache(F); + }; + return inlineCallsImpl(SCC, CG, GetAssumptionCache, PSI, TLI, InsertLifetime, + [this](CallSite CS) { return getInlineCost(CS); }, + AARGetter); +} + /// Remove now-dead linkonce functions at the end of /// processing to avoid breaking the SCC traversal. bool Inliner::doFinalization(CallGraph &CG) { @@ -674,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: lib/Transforms/IPO/SampleProfile.cpp =================================================================== --- lib/Transforms/IPO/SampleProfile.cpp +++ lib/Transforms/IPO/SampleProfile.cpp @@ -695,6 +695,8 @@ bool SampleProfileLoader::inlineHotFunctions(Function &F) { bool Changed = false; LLVMContext &Ctx = F.getContext(); + std::function GetAssumptionCache = [&]( + Function &F) -> AssumptionCache & { return ACT->getAssumptionCache(F); }; while (true) { bool LocalChanged = false; SmallVector CIS; @@ -706,7 +708,7 @@ } } for (auto CI : CIS) { - InlineFunctionInfo IFI(nullptr, ACT); + InlineFunctionInfo IFI(nullptr, ACT ? &GetAssumptionCache : nullptr); Function *CalledFunction = CI->getCalledFunction(); DebugLoc DLoc = CI->getDebugLoc(); uint64_t NumSamples = findCalleeFunctionSamples(*CI)->getTotalSamples(); Index: lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- lib/Transforms/Utils/InlineFunction.cpp +++ lib/Transforms/Utils/InlineFunction.cpp @@ -1078,7 +1078,7 @@ // caller, then don't bother inserting the assumption. Value *Arg = CS.getArgument(I->getArgNo()); if (getKnownAlignment(Arg, DL, CS.getInstruction(), - &IFI.ACT->getAssumptionCache(*CS.getCaller()), + &(*IFI.GetAssumptionCache)(*CS.getCaller()), &DT) >= Align) continue; @@ -1199,7 +1199,7 @@ // If the pointer is already known to be sufficiently aligned, or if we can // round it up to a larger alignment, then we don't need a temporary. if (getOrEnforceKnownAlignment(Arg, ByValAlignment, DL, TheCall, - &IFI.ACT->getAssumptionCache(*Caller)) >= + &(*IFI.GetAssumptionCache)(*Caller)) >= ByValAlignment) return Arg; @@ -1604,8 +1604,8 @@ // FIXME: We could register any cloned assumptions instead of clearing the // whole function's cache. - if (IFI.ACT) - IFI.ACT->getAssumptionCache(*Caller).clear(); + if (IFI.GetAssumptionCache) + (*IFI.GetAssumptionCache)(*Caller).clear(); } // If there are any alloca instructions in the block that used to be the entry @@ -2125,7 +2125,7 @@ if (PHI) { auto &DL = Caller->getParent()->getDataLayout(); if (Value *V = SimplifyInstruction(PHI, DL, nullptr, nullptr, - &IFI.ACT->getAssumptionCache(*Caller))) { + &(*IFI.GetAssumptionCache)(*Caller))) { PHI->replaceAllUsesWith(V); PHI->eraseFromParent(); } 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); } }