From: Chris Lattner Date: Thu, 31 Jan 2002 18:32:27 +0000 (+0000) Subject: * Make debugging output nicer X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=ce885e9f9d03fa1d9dd5e2abba5e95953473288f;p=oota-llvm.git * Make debugging output nicer * Implement pass memory freeing after the pass is unused * Expose PassManager typedef in Pass.h instead of PassManager.h git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1617 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h index f43db85cbbd..78cc92a2397 100644 --- a/include/llvm/Pass.h +++ b/include/llvm/Pass.h @@ -29,6 +29,11 @@ class Pass; template class PassManagerT; struct AnalysisResolver; +// PassManager - Top level PassManagerT instantiation intended to be used. +// Implemented in PassManager.h +typedef PassManagerT PassManager; + + //===----------------------------------------------------------------------===// // Pass interface - Implemented by all 'passes'. Subclass this if you are an // interprocedural optimization or you do not fit into any of the more @@ -69,6 +74,19 @@ public: // By default, no analysis results are used or destroyed. } + // releaseMemory() - This member can be implemented by a pass if it wants to + // be able to release its memory when it is no longer needed. The default + // behavior of passes is to hold onto memory for the entire duration of their + // lifetime (which is the entire compile time). For pipelined passes, this + // is not a big deal because that memory gets recycled every time the pass is + // invoked on another program unit. For IP passes, it is more important to + // free memory when it is unused. + // + // Optionally implement this function to release pass memory when it is no + // longer used. + // + virtual void releaseMemory() {} + #ifndef NDEBUG // dumpPassStructure - Implement the -debug-passes=PassStructure option virtual void dumpPassStructure(unsigned Offset = 0); @@ -89,9 +107,8 @@ private: friend class PassManagerT; friend class PassManagerT; friend class PassManagerT; - virtual void addToPassManager(PassManagerT *PM, - AnalysisSet &Destroyed, - AnalysisSet &Provided); + virtual void addToPassManager(PassManagerT *PM, AnalysisSet &Req, + AnalysisSet &Destroyed, AnalysisSet &Provided); }; @@ -132,10 +149,10 @@ private: friend class PassManagerT; friend class PassManagerT; friend class PassManagerT; - virtual void addToPassManager(PassManagerT *PM,AnalysisSet &Destroyed, - AnalysisSet &Provided); - virtual void addToPassManager(PassManagerT *PM,AnalysisSet &Destroyed, - AnalysisSet &Provided); + virtual void addToPassManager(PassManagerT *PM, AnalysisSet &Req, + AnalysisSet &Dest, AnalysisSet &Prov); + virtual void addToPassManager(PassManagerT *PM,AnalysisSet &Req, + AnalysisSet &Dest, AnalysisSet &Prov); }; @@ -169,11 +186,10 @@ struct BasicBlockPass : public MethodPass { private: friend class PassManagerT; friend class PassManagerT; - virtual void addToPassManager(PassManagerT *PM,AnalysisSet &Destroyed, - AnalysisSet &Provided); - virtual void addToPassManager(PassManagerT *PM, - AnalysisSet &Destroyed, - AnalysisSet &Provided); + virtual void addToPassManager(PassManagerT *PM, AnalysisSet &, + AnalysisSet &, AnalysisSet &); + virtual void addToPassManager(PassManagerT *PM, AnalysisSet &, + AnalysisSet &, AnalysisSet &); }; @@ -228,14 +244,16 @@ public: // is used to pull analysis information out of them. // struct AnalysisResolver { - virtual Pass *getAnalysisOrNullUp(AnalysisID ID) = 0; - virtual Pass *getAnalysisOrNullDown(AnalysisID ID) = 0; + virtual Pass *getAnalysisOrNullUp(AnalysisID ID) const = 0; + virtual Pass *getAnalysisOrNullDown(AnalysisID ID) const = 0; Pass *getAnalysis(AnalysisID ID) { Pass *Result = getAnalysisOrNullUp(ID); assert(Result && "Pass has an incorrect analysis uses set!"); return Result; } virtual unsigned getDepth() const = 0; + + virtual void markPassUsed(AnalysisID P, Pass *User) = 0; protected: void setAnalysisResolver(Pass *P, AnalysisResolver *AR); }; diff --git a/lib/VMCore/Pass.cpp b/lib/VMCore/Pass.cpp index a139a25e4d6..c18ff0adcc5 100644 --- a/lib/VMCore/Pass.cpp +++ b/lib/VMCore/Pass.cpp @@ -51,7 +51,7 @@ void PMDebug::PrintPassStructure(Pass *P) { void PMDebug::PrintPassInformation(unsigned Depth, const char *Action, Pass *P, Value *V) { if (PassDebugging >= PassExecutions) { - std::cerr << std::string(Depth*2, ' ') << Action << " '" + std::cerr << (void*)P << std::string(Depth*2+1, ' ') << Action << " '" << typeid(*P).name(); if (V) { std::cerr << "' on "; @@ -71,9 +71,9 @@ void PMDebug::PrintPassInformation(unsigned Depth, const char *Action, } void PMDebug::PrintAnalysisSetInfo(unsigned Depth, const char *Msg, - const Pass::AnalysisSet &Set) { + Pass *P, const Pass::AnalysisSet &Set) { if (PassDebugging >= PassDetails && !Set.empty()) { - std::cerr << std::string(Depth*2+2, ' ') << Msg << " Analyses:"; + std::cerr << (void*)P << std::string(Depth*2+3, ' ') << Msg << " Analyses:"; for (unsigned i = 0; i < Set.size(); ++i) { Pass *P = Set[i].createPass(); // Good thing this is just debug code... std::cerr << " " << typeid(*P).name(); @@ -94,9 +94,9 @@ void Pass::dumpPassStructure(unsigned Offset = 0) { // Pass Implementation // -void Pass::addToPassManager(PassManagerT *PM, AnalysisSet &Destroyed, - AnalysisSet &Provided) { - PM->addPass(this, Destroyed, Provided); +void Pass::addToPassManager(PassManagerT *PM, AnalysisSet &Required, + AnalysisSet &Destroyed, AnalysisSet &Provided) { + PM->addPass(this, Required, Destroyed, Provided); } //===----------------------------------------------------------------------===// @@ -126,15 +126,15 @@ bool MethodPass::run(Method *M) { } void MethodPass::addToPassManager(PassManagerT *PM, - AnalysisSet &Destroyed, + AnalysisSet &Required, AnalysisSet &Destroyed, AnalysisSet &Provided) { - PM->addPass(this, Destroyed, Provided); + PM->addPass(this, Required, Destroyed, Provided); } void MethodPass::addToPassManager(PassManagerT *PM, - AnalysisSet &Destroyed, + AnalysisSet &Required, AnalysisSet &Destroyed, AnalysisSet &Provided) { - PM->addPass(this, Destroyed, Provided); + PM->addPass(this, Required, Destroyed, Provided); } //===----------------------------------------------------------------------===// @@ -160,14 +160,16 @@ bool BasicBlockPass::run(BasicBlock *BB) { } void BasicBlockPass::addToPassManager(PassManagerT *PM, + AnalysisSet &Required, AnalysisSet &Destroyed, AnalysisSet &Provided) { - PM->addPass(this, Destroyed, Provided); + PM->addPass(this, Required, Destroyed, Provided); } void BasicBlockPass::addToPassManager(PassManagerT *PM, + AnalysisSet &Required, AnalysisSet &Destroyed, AnalysisSet &Provided) { - PM->addPass(this, Destroyed, Provided); + PM->addPass(this, Required, Destroyed, Provided); } diff --git a/lib/VMCore/PassManagerT.h b/lib/VMCore/PassManagerT.h index 70f2cde66ea..5583b9b9187 100644 --- a/lib/VMCore/PassManagerT.h +++ b/lib/VMCore/PassManagerT.h @@ -15,10 +15,6 @@ #include "llvm/Pass.h" #include -// PassManager - Top level PassManagerT instantiation intended to be used. -typedef PassManagerT PassManager; - - //===----------------------------------------------------------------------===// // PMDebug class - a set of debugging functions that are enabled when compiling // with -g on. If compiling at -O, all functions are inlined noops. @@ -27,7 +23,7 @@ struct PMDebug { #ifdef NDEBUG inline static void PrintPassStructure(Pass *) {} inline static void PrintPassInformation(unsigned,const char*,Pass*,Value*) {} - inline static void PrintAnalysisSetInfo(unsigned,const char*, + inline static void PrintAnalysisSetInfo(unsigned,const char*,Pass *P, const Pass::AnalysisSet &) {} #else // If compiled in debug mode, these functions can be enabled by setting @@ -35,7 +31,8 @@ struct PMDebug { // static void PrintPassStructure(Pass *P); static void PrintPassInformation(unsigned,const char*,Pass *, Value *); - static void PrintAnalysisSetInfo(unsigned,const char*,const Pass::AnalysisSet&); + static void PrintAnalysisSetInfo(unsigned,const char*,Pass *P, + const Pass::AnalysisSet&); #endif }; @@ -67,7 +64,7 @@ class PassManagerT : public PassManagerTraits,public AnalysisResolver{ std::vector Passes; // List of pass's to run // The parent of this pass manager... - const ParentClass *Parent; + ParentClass * const Parent; // The current batcher if one is in use, or null BatcherClass *Batcher; @@ -78,6 +75,12 @@ class PassManagerT : public PassManagerTraits,public AnalysisResolver{ // std::map CurrentAnalyses; + // LastUseOf - This map keeps track of the last usage in our pipeline of a + // particular pass. When executing passes, the memory for .first is free'd + // after .second is run. + // + std::map LastUseOf; + public: PassManagerT(ParentClass *Par = 0) : Parent(Par), Batcher(0) {} ~PassManagerT() { @@ -94,6 +97,13 @@ public: closeBatcher(); CurrentAnalyses.clear(); + // LastUserOf - This contains the inverted LastUseOfMap... + std::map > LastUserOf; + for (std::map::iterator I = LastUseOf.begin(), + E = LastUseOf.end(); I != E; ++I) + LastUserOf[I->second].push_back(I->first); + + // Output debug information... if (Parent == 0) PMDebug::PrintPassStructure(this); @@ -107,7 +117,7 @@ public: std::vector Required, Destroyed, Provided; P->getAnalysisUsageInfo(Required, Destroyed, Provided); - PMDebug::PrintAnalysisSetInfo(getDepth(), "Required", Required); + PMDebug::PrintAnalysisSetInfo(getDepth(), "Required", P, Required); #ifndef NDEBUG // All Required analyses should be available to the pass as it runs! @@ -120,8 +130,8 @@ public: // Run the sub pass! MadeChanges |= Traits::runPass(P, M); - PMDebug::PrintAnalysisSetInfo(getDepth(), "Destroyed", Destroyed); - PMDebug::PrintAnalysisSetInfo(getDepth(), "Provided", Provided); + PMDebug::PrintAnalysisSetInfo(getDepth(), "Destroyed", P, Destroyed); + PMDebug::PrintAnalysisSetInfo(getDepth(), "Provided", P, Provided); // Erase all analyses in the destroyed set... for (Pass::AnalysisSet::iterator I = Destroyed.begin(), @@ -132,47 +142,43 @@ public: for (Pass::AnalysisSet::iterator I = Provided.begin(), E = Provided.end(); I != E; ++I) CurrentAnalyses[*I] = P; - } - return MadeChanges; - } - - // add - Add a pass to the queue of passes to run. This passes ownership of - // the Pass to the PassManager. When the PassManager is destroyed, the pass - // will be destroyed as well, so there is no need to delete the pass. Also, - // all passes MUST be new'd. - // - void add(PassClass *P) { - // Get information about what analyses the pass uses... - std::vector Required, Destroyed, Provided; - P->getAnalysisUsageInfo(Required, Destroyed, Provided); - // Loop over all of the analyses used by this pass, - for (std::vector::iterator I = Required.begin(), - E = Required.end(); I != E; ++I) { - if (getAnalysisOrNullDown(*I) == 0) - add((PassClass*)I->createPass()); + // Free memory for any passes that we are the last use of... + std::vector &DeadPass = LastUserOf[P]; + for (std::vector::iterator I = DeadPass.begin(),E = DeadPass.end(); + I != E; ++I) { + PMDebug::PrintPassInformation(getDepth()+1, "Freeing Pass", *I, + (Value*)M); + (*I)->releaseMemory(); + } } - - // Tell the pass to add itself to this PassManager... the way it does so - // depends on the class of the pass, and is critical to laying out passes in - // an optimal order.. - // - P->addToPassManager(this, Destroyed, Provided); + return MadeChanges; } #ifndef NDEBUG // dumpPassStructure - Implement the -debug-passes=PassStructure option virtual void dumpPassStructure(unsigned Offset = 0) { - std::cerr << std::string(Offset*2, ' ') << "Pass Manager\n"; + std::cerr << std::string(Offset*2, ' ') << Traits::getPMName() + << " Pass Manager\n"; for (std::vector::iterator I = Passes.begin(), E = Passes.end(); - I != E; ++I) - (*I)->dumpPassStructure(Offset+1); + I != E; ++I) { + PassClass *P = *I; + P->dumpPassStructure(Offset+1); + + // Loop through and see which classes are destroyed after this one... + for (std::map::iterator I = LastUseOf.begin(), + E = LastUseOf.end(); I != E; ++I) { + if (P == I->second) { + std::cerr << "Fr" << std::string(Offset*2, ' '); + I->first->dumpPassStructure(0); + } + } + } } #endif -public: - Pass *getAnalysisOrNullDown(AnalysisID ID) { - std::map::iterator I = CurrentAnalyses.find(ID); + Pass *getAnalysisOrNullDown(AnalysisID ID) const { + std::map::const_iterator I = CurrentAnalyses.find(ID); if (I == CurrentAnalyses.end()) { if (Batcher) return ((AnalysisResolver*)Batcher)->getAnalysisOrNullDown(ID); @@ -181,19 +187,64 @@ public: return I->second; } - Pass *getAnalysisOrNullUp(AnalysisID ID) { - std::map::iterator I = CurrentAnalyses.find(ID); + Pass *getAnalysisOrNullUp(AnalysisID ID) const { + std::map::const_iterator I = CurrentAnalyses.find(ID); if (I == CurrentAnalyses.end()) { if (Parent) - return ((AnalysisResolver*)Parent)->getAnalysisOrNullUp(ID); + return Parent->getAnalysisOrNullUp(ID); return 0; } return I->second; } + // markPassUsed - Inform higher level pass managers (and ourselves) + // that these analyses are being used by this pass. This is used to + // make sure that analyses are not free'd before we have to use + // them... + // + void markPassUsed(AnalysisID P, Pass *User) { + std::map::iterator I = CurrentAnalyses.find(P); + if (I != CurrentAnalyses.end()) { + LastUseOf[I->second] = User; // Local pass, extend the lifetime + } else { + // Pass not in current available set, must be a higher level pass + // available to us, propogate to parent pass manager... We tell the + // parent that we (the passmanager) are using the analysis so that it + // frees the analysis AFTER this pass manager runs. + // + assert(Parent != 0 && "Pass available but not found!"); + Parent->markPassUsed(P, this); + } + } + + // Return the number of parent PassManagers that exist virtual unsigned getDepth() const { if (Parent == 0) return 0; - return 1 + ((AnalysisResolver*)Parent)->getDepth(); + return 1 + Parent->getDepth(); + } + + // add - Add a pass to the queue of passes to run. This passes ownership of + // the Pass to the PassManager. When the PassManager is destroyed, the pass + // will be destroyed as well, so there is no need to delete the pass. This + // implies that all passes MUST be new'd. + // + void add(PassClass *P) { + // Get information about what analyses the pass uses... + std::vector Required, Destroyed, Provided; + P->getAnalysisUsageInfo(Required, Destroyed, Provided); + + // Loop over all of the analyses used by this pass, + for (std::vector::iterator I = Required.begin(), + E = Required.end(); I != E; ++I) { + if (getAnalysisOrNullDown(*I) == 0) + add((PassClass*)I->createPass()); + } + + // Tell the pass to add itself to this PassManager... the way it does so + // depends on the class of the pass, and is critical to laying out passes in + // an optimal order.. + // + P->addToPassManager(this, Required, Destroyed, Provided); } private: @@ -208,8 +259,8 @@ private: // add the pass to the end of the pass list and terminate any accumulation of // MethodPasses that are present. // - void addPass(PassClass *P, Pass::AnalysisSet &Destroyed, - Pass::AnalysisSet &Provided) { + void addPass(PassClass *P, Pass::AnalysisSet &Required, + Pass::AnalysisSet &Destroyed, Pass::AnalysisSet &Provided) { // Providers are analysis classes which are forbidden to modify the module // they are operating on, so they are allowed to be reordered to before the // batcher... @@ -223,6 +274,14 @@ private: setAnalysisResolver(P, this); Passes.push_back(P); + // Inform higher level pass managers (and ourselves) that these analyses are + // being used by this pass. This is used to make sure that analyses are not + // free'd before we have to use them... + // + for (std::vector::iterator I = Required.begin(), + E = Required.end(); I != E; ++I) + markPassUsed(*I, P); // Mark *I as used by P + // Erase all analyses in the destroyed set... for (std::vector::iterator I = Destroyed.begin(), E = Destroyed.end(); I != E; ++I) @@ -232,18 +291,21 @@ private: for (std::vector::iterator I = Provided.begin(), E = Provided.end(); I != E; ++I) CurrentAnalyses[*I] = P; + + // For now assume that our results are never used... + LastUseOf[P] = P; } // For MethodPass subclasses, we must be sure to batch the MethodPasses // together in a MethodPassBatcher object so that all of the analyses are run // together a method at a time. // - void addPass(SubPassClass *MP, Pass::AnalysisSet &Destroyed, - Pass::AnalysisSet &Provided) { + void addPass(SubPassClass *MP, Pass::AnalysisSet &Required, + Pass::AnalysisSet &Destroyed, Pass::AnalysisSet &Provided) { if (Batcher == 0) // If we don't have a batcher yet, make one now. Batcher = new BatcherClass(this); // The Batcher will queue them passes up - MP->addToPassManager(Batcher, Destroyed, Provided); + MP->addToPassManager(Batcher, Required, Destroyed, Provided); } // closeBatcher - Terminate the batcher that is being worked on. @@ -291,6 +353,10 @@ template<> struct PassManagerTraits : public BasicBlockPass { return P->runOnBasicBlock(M); } + // getPMName() - Return the name of the unit the PassManager operates on for + // debugging. + const char *getPMName() const { return "BasicBlock"; } + // Implement the BasicBlockPass interface... virtual bool doInitialization(Module *M); virtual bool runOnBasicBlock(BasicBlock *BB); @@ -326,6 +392,10 @@ template<> struct PassManagerTraits : public MethodPass { return P->runOnMethod(M); } + // getPMName() - Return the name of the unit the PassManager operates on for + // debugging. + const char *getPMName() const { return "Method"; } + // Implement the MethodPass interface... virtual bool doInitialization(Module *M); virtual bool runOnMethod(Method *M); @@ -350,11 +420,15 @@ template<> struct PassManagerTraits : public Pass { typedef PassManagerT BatcherClass; // ParentClass - The type of the parent PassManager... - typedef void ParentClass; + typedef AnalysisResolver ParentClass; // runPass - Specify how the pass should be run on the UnitType static bool runPass(PassClass *P, Module *M) { return P->run(M); } + // getPMName() - Return the name of the unit the PassManager operates on for + // debugging. + const char *getPMName() const { return "Module"; } + // run - Implement the Pass interface... virtual bool run(Module *M) { return ((PassManagerT*)this)->runOnUnit(M);