//===- LegacyPassManagers.h - Legacy Pass Infrastructure --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file declares the LLVM Pass Manager infrastructure. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_LEGACYPASSMANAGERS_H #define LLVM_IR_LEGACYPASSMANAGERS_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Pass.h" #include //===----------------------------------------------------------------------===// // Overview: // The Pass Manager Infrastructure manages passes. It's responsibilities are: // // o Manage optimization pass execution order // o Make required Analysis information available before pass P is run // o Release memory occupied by dead passes // o If Analysis information is dirtied by a pass then regenerate Analysis // information before it is consumed by another pass. // // Pass Manager Infrastructure uses multiple pass managers. They are // PassManager, FunctionPassManager, MPPassManager, FPPassManager, BBPassManager. // This class hierarchy uses multiple inheritance but pass managers do not // derive from another pass manager. // // PassManager and FunctionPassManager are two top-level pass manager that // represents the external interface of this entire pass manager infrastucture. // // Important classes : // // [o] class PMTopLevelManager; // // Two top level managers, PassManager and FunctionPassManager, derive from // PMTopLevelManager. PMTopLevelManager manages information used by top level // managers such as last user info. // // [o] class PMDataManager; // // PMDataManager manages information, e.g. list of available analysis info, // used by a pass manager to manage execution order of passes. It also provides // a place to implement common pass manager APIs. All pass managers derive from // PMDataManager. // // [o] class FunctionPassManager; // // This is a external interface used to manage FunctionPasses. This // interface relies on FunctionPassManagerImpl to do all the tasks. // // [o] class FunctionPassManagerImpl : public ModulePass, PMDataManager, // public PMTopLevelManager; // // FunctionPassManagerImpl is a top level manager. It manages FPPassManagers // // [o] class FPPassManager : public ModulePass, public PMDataManager; // // FPPassManager manages FunctionPasses and BBPassManagers // // [o] class MPPassManager : public Pass, public PMDataManager; // // MPPassManager manages ModulePasses and FPPassManagers // // [o] class PassManager; // // This is a external interface used by various tools to manages passes. It // relies on PassManagerImpl to do all the tasks. // // [o] class PassManagerImpl : public Pass, public PMDataManager, // public PMTopLevelManager // // PassManagerImpl is a top level pass manager responsible for managing // MPPassManagers. //===----------------------------------------------------------------------===// #include "llvm/Support/PrettyStackTrace.h" namespace llvm { template class ArrayRef; class Module; class StringRef; class Value; class PMDataManager; // enums for debugging strings enum PassDebuggingString { EXECUTION_MSG, // "Executing Pass '" + PassName MODIFICATION_MSG, // "Made Modification '" + PassName FREEING_MSG, // " Freeing Pass '" + PassName ON_FUNCTION_MSG, // "' on Function '" + FunctionName + "'...\n" ON_MODULE_MSG, // "' on Module '" + ModuleName + "'...\n" ON_REGION_MSG, // "' on Region '" + Msg + "'...\n'" ON_LOOP_MSG, // "' on Loop '" + Msg + "'...\n'" ON_CG_MSG // "' on Call Graph Nodes '" + Msg + "'...\n'" }; /// PassManagerPrettyStackEntry - This is used to print informative information /// about what pass is running when/if a stack trace is generated. class PassManagerPrettyStackEntry : public PrettyStackTraceEntry { Pass *P; Value *V; Module *M; public: explicit PassManagerPrettyStackEntry(Pass *p) : P(p), V(nullptr), M(nullptr) {} // When P is releaseMemory'd. PassManagerPrettyStackEntry(Pass *p, Value &v) : P(p), V(&v), M(nullptr) {} // When P is run on V PassManagerPrettyStackEntry(Pass *p, Module &m) : P(p), V(nullptr), M(&m) {} // When P is run on M /// print - Emit information about this stack frame to OS. void print(raw_ostream &OS) const override; }; //===----------------------------------------------------------------------===// // PMStack // /// PMStack - This class implements a stack data structure of PMDataManager /// pointers. /// /// Top level pass managers (see PassManager.cpp) maintain active Pass Managers /// using PMStack. Each Pass implements assignPassManager() to connect itself /// with appropriate manager. assignPassManager() walks PMStack to find /// suitable manager. class PMStack { public: typedef std::vector::const_reverse_iterator iterator; iterator begin() const { return S.rbegin(); } iterator end() const { return S.rend(); } void pop(); PMDataManager *top() const { return S.back(); } void push(PMDataManager *PM); bool empty() const { return S.empty(); } void dump() const; private: std::vector S; }; //===----------------------------------------------------------------------===// // PMTopLevelManager // /// PMTopLevelManager manages LastUser info and collects common APIs used by /// top level pass managers. class PMTopLevelManager { protected: explicit PMTopLevelManager(PMDataManager *PMDM); unsigned getNumContainedManagers() const { return (unsigned)PassManagers.size(); } void initializeAllAnalysisInfo(); private: virtual PMDataManager *getAsPMDataManager() = 0; virtual PassManagerType getTopLevelPassManagerType() = 0; public: /// Schedule pass P for execution. Make sure that passes required by /// P are run before P is run. Update analysis info maintained by /// the manager. Remove dead passes. This is a recursive function. void schedulePass(Pass *P); /// Set pass P as the last user of the given analysis passes. void setLastUser(ArrayRef AnalysisPasses, Pass *P); /// Collect passes whose last user is P void collectLastUses(SmallVectorImpl &LastUses, Pass *P); /// Find the pass that implements Analysis AID. Search immutable /// passes and all pass managers. If desired pass is not found /// then return NULL. Pass *findAnalysisPass(AnalysisID AID); /// Retrieve the PassInfo for an analysis. const PassInfo *findAnalysisPassInfo(AnalysisID AID) const; /// Find analysis usage information for the pass P. AnalysisUsage *findAnalysisUsage(Pass *P); virtual ~PMTopLevelManager(); /// Add immutable pass and initialize it. void addImmutablePass(ImmutablePass *P); inline SmallVectorImpl& getImmutablePasses() { return ImmutablePasses; } void addPassManager(PMDataManager *Manager) { PassManagers.push_back(Manager); } // Add Manager into the list of managers that are not directly // maintained by this top level pass manager inline void addIndirectPassManager(PMDataManager *Manager) { IndirectPassManagers.push_back(Manager); } // Print passes managed by this top level manager. void dumpPasses() const; void dumpArguments() const; // Active Pass Managers PMStack activeStack; protected: /// Collection of pass managers SmallVector PassManagers; private: /// Collection of pass managers that are not directly maintained /// by this pass manager SmallVector IndirectPassManagers; // Map to keep track of last user of the analysis pass. // LastUser->second is the last user of Lastuser->first. // This is kept in sync with InversedLastUser. DenseMap LastUser; // Map to keep track of passes that are last used by a pass. // This is kept in sync with LastUser. DenseMap > InversedLastUser; /// Immutable passes are managed by top level manager. SmallVector ImmutablePasses; /// Map from ID to immutable passes. SmallDenseMap ImmutablePassMap; /// A wrapper around AnalysisUsage for the purpose of uniqueing. The wrapper /// is used to avoid needing to make AnalysisUsage itself a folding set node. struct AUFoldingSetNode : public FoldingSetNode { AnalysisUsage AU; AUFoldingSetNode(const AnalysisUsage &AU) : AU(AU) {} void Profile(FoldingSetNodeID &ID) const { Profile(ID, AU); } static void Profile(FoldingSetNodeID &ID, const AnalysisUsage &AU) { // TODO: We could consider sorting the dependency arrays within the // AnalysisUsage (since they are conceptually unordered). ID.AddBoolean(AU.getPreservesAll()); auto ProfileVec = [&](const SmallVectorImpl& Vec) { ID.AddInteger(Vec.size()); for(AnalysisID AID : Vec) ID.AddPointer(AID); }; ProfileVec(AU.getRequiredSet()); ProfileVec(AU.getRequiredTransitiveSet()); ProfileVec(AU.getPreservedSet()); ProfileVec(AU.getUsedSet()); } }; // Contains all of the unique combinations of AnalysisUsage. This is helpful // when we have multiple instances of the same pass since they'll usually // have the same analysis usage and can share storage. FoldingSet UniqueAnalysisUsages; // Allocator used for allocating UAFoldingSetNodes. This handles deletion of // all allocated nodes in one fell swoop. SpecificBumpPtrAllocator AUFoldingSetNodeAllocator; // Maps from a pass to it's associated entry in UniqueAnalysisUsages. Does // not own the storage associated with either key or value.. DenseMap AnUsageMap; /// Collection of PassInfo objects found via analysis IDs and in this top /// level manager. This is used to memoize queries to the pass registry. /// FIXME: This is an egregious hack because querying the pass registry is /// either slow or racy. mutable DenseMap AnalysisPassInfos; }; //===----------------------------------------------------------------------===// // PMDataManager /// PMDataManager provides the common place to manage the analysis data /// used by pass managers. class PMDataManager { public: explicit PMDataManager() { initializeAnalysisInfo(); } virtual ~PMDataManager(); virtual Pass *getAsPass() = 0; /// Augment AvailableAnalysis by adding analysis made available by pass P. void recordAvailableAnalysis(Pass *P); /// verifyPreservedAnalysis -- Verify analysis presreved by pass P. void verifyPreservedAnalysis(Pass *P); /// Remove Analysis that is not preserved by the pass void removeNotPreservedAnalysis(Pass *P); /// Remove dead passes used by P. void removeDeadPasses(Pass *P, StringRef Msg, enum PassDebuggingString); /// Remove P. void freePass(Pass *P, StringRef Msg, enum PassDebuggingString); /// Add pass P into the PassVector. Update /// AvailableAnalysis appropriately if ProcessAnalysis is true. void add(Pass *P, bool ProcessAnalysis = true); /// Add RequiredPass into list of lower level passes required by pass P. /// RequiredPass is run on the fly by Pass Manager when P requests it /// through getAnalysis interface. virtual void addLowerLevelRequiredPass(Pass *P, Pass *RequiredPass); virtual std::tuple getOnTheFlyPass(Pass *P, AnalysisID PI, Function &F); /// Initialize available analysis information. void initializeAnalysisInfo() { AvailableAnalysis.clear(); for (auto &IA : InheritedAnalysis) IA = nullptr; } // Return true if P preserves high level analysis used by other // passes that are managed by this manager. bool preserveHigherLevelAnalysis(Pass *P); /// Populate UsedPasses with analysis pass that are used or required by pass /// P and are available. Populate ReqPassNotAvailable with analysis pass that /// are required by pass P but are not available. void collectRequiredAndUsedAnalyses( SmallVectorImpl &UsedPasses, SmallVectorImpl &ReqPassNotAvailable, Pass *P); /// All Required analyses should be available to the pass as it runs! Here /// we fill in the AnalysisImpls member of the pass so that it can /// successfully use the getAnalysis() method to retrieve the /// implementations it needs. void initializeAnalysisImpl(Pass *P); /// Find the pass that implements Analysis AID. If desired pass is not found /// then return NULL. Pass *findAnalysisPass(AnalysisID AID, bool Direction); // Access toplevel manager PMTopLevelManager *getTopLevelManager() { return TPM; } void setTopLevelManager(PMTopLevelManager *T) { TPM = T; } unsigned getDepth() const { return Depth; } void setDepth(unsigned newDepth) { Depth = newDepth; } // Print routines used by debug-pass void dumpLastUses(Pass *P, unsigned Offset) const; void dumpPassArguments() const; void dumpPassInfo(Pass *P, enum PassDebuggingString S1, enum PassDebuggingString S2, StringRef Msg); void dumpRequiredSet(const Pass *P) const; void dumpPreservedSet(const Pass *P) const; void dumpUsedSet(const Pass *P) const; unsigned getNumContainedPasses() const { return (unsigned)PassVector.size(); } virtual PassManagerType getPassManagerType() const { assert ( 0 && "Invalid use of getPassManagerType"); return PMT_Unknown; } DenseMap *getAvailableAnalysis() { return &AvailableAnalysis; } // Collect AvailableAnalysis from all the active Pass Managers. void populateInheritedAnalysis(PMStack &PMS) { unsigned Index = 0; for (PMDataManager *PMDM : PMS) InheritedAnalysis[Index++] = PMDM->getAvailableAnalysis(); } /// Set the initial size of the module if the user has specified that they /// want remarks for size. /// Returns 0 if the remark was not requested. unsigned initSizeRemarkInfo( Module &M, StringMap> &FunctionToInstrCount); /// Emit a remark signifying that the number of IR instructions in the module /// changed. /// \p F is optionally passed by passes which run on Functions, and thus /// always know whether or not a non-empty function is available. /// /// \p FunctionToInstrCount maps the name of a \p Function to a pair. The /// first member of the pair is the IR count of the \p Function before running /// \p P, and the second member is the IR count of the \p Function after /// running \p P. void emitInstrCountChangedRemark( Pass *P, Module &M, int64_t Delta, unsigned CountBefore, StringMap> &FunctionToInstrCount, Function *F = nullptr); protected: // Top level manager. PMTopLevelManager *TPM = nullptr; // Collection of pass that are managed by this manager SmallVector PassVector; // Collection of Analysis provided by Parent pass manager and // used by current pass manager. At any time there can not be more // then PMT_Last active pass managers. DenseMap *InheritedAnalysis[PMT_Last]; /// isPassDebuggingExecutionsOrMore - Return true if -debug-pass=Executions /// or higher is specified. bool isPassDebuggingExecutionsOrMore() const; private: void dumpAnalysisUsage(StringRef Msg, const Pass *P, const AnalysisUsage::VectorType &Set) const; // Set of available Analysis. This information is used while scheduling // pass. If a pass requires an analysis which is not available then // the required analysis pass is scheduled to run before the pass itself is // scheduled to run. DenseMap AvailableAnalysis; // Collection of higher level analysis used by the pass managed by // this manager. SmallVector HigherLevelAnalysis; unsigned Depth = 0; }; //===----------------------------------------------------------------------===// // FPPassManager // /// FPPassManager manages BBPassManagers and FunctionPasses. /// It batches all function passes and basic block pass managers together and /// sequence them to process one function at a time before processing next /// function. class FPPassManager : public ModulePass, public PMDataManager { public: static char ID; explicit FPPassManager() : ModulePass(ID) {} /// run - Execute all of the passes scheduled for execution. Keep track of /// whether any of the passes modifies the module, and if so, return true. bool runOnFunction(Function &F); bool runOnModule(Module &M) override; /// cleanup - After running all passes, clean up pass manager cache. void cleanup(); /// doInitialization - Overrides ModulePass doInitialization for global /// initialization tasks /// using ModulePass::doInitialization; /// doInitialization - Run all of the initializers for the function passes. /// bool doInitialization(Module &M) override; /// doFinalization - Overrides ModulePass doFinalization for global /// finalization tasks /// using ModulePass::doFinalization; /// doFinalization - Run all of the finalizers for the function passes. /// bool doFinalization(Module &M) override; PMDataManager *getAsPMDataManager() override { return this; } Pass *getAsPass() override { return this; } /// Pass Manager itself does not invalidate any analysis info. void getAnalysisUsage(AnalysisUsage &Info) const override { Info.setPreservesAll(); } // Print passes managed by this manager void dumpPassStructure(unsigned Offset) override; StringRef getPassName() const override { return "Function Pass Manager"; } FunctionPass *getContainedPass(unsigned N) { assert ( N < PassVector.size() && "Pass number out of range!"); FunctionPass *FP = static_cast(PassVector[N]); return FP; } PassManagerType getPassManagerType() const override { return PMT_FunctionPassManager; } }; } #endif