//===- DataStructure.h - Build data structure graphs ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Implement the LLVM data structure analysis library. // //===----------------------------------------------------------------------===// #ifndef LLVM_ANALYSIS_DATA_STRUCTURE_H #define LLVM_ANALYSIS_DATA_STRUCTURE_H #include "llvm/Pass.h" #include "llvm/Target/TargetData.h" #include "llvm/ADT/hash_map" #include "llvm/ADT/hash_set" #include "llvm/ADT/EquivalenceClasses.h" namespace llvm { class Type; class Instruction; class GlobalValue; class CallSite; class DSGraph; class DSCallSite; class DSNode; class DSNodeHandle; FunctionPass *createDataStructureStatsPass(); FunctionPass *createDataStructureGraphCheckerPass(); // FIXME: move this stuff to a private header namespace DataStructureAnalysis { /// isPointerType - Return true if this first class type is big enough to hold /// a pointer. /// bool isPointerType(const Type *Ty); } // LocalDataStructures - The analysis that computes the local data structure // graphs for all of the functions in the program. // // FIXME: This should be a Function pass that can be USED by a Pass, and would // be automatically preserved. Until we can do that, this is a Pass. // class LocalDataStructures : public ModulePass { // DSInfo, one graph for each function hash_map DSInfo; DSGraph *GlobalsGraph; /// GlobalECs - The equivalence classes for each global value that is merged /// with other global values in the DSGraphs. EquivalenceClasses GlobalECs; public: ~LocalDataStructures() { releaseMemory(); } virtual bool runOnModule(Module &M); bool hasGraph(const Function &F) const { return DSInfo.find(const_cast(&F)) != DSInfo.end(); } /// getDSGraph - Return the data structure graph for the specified function. /// DSGraph &getDSGraph(const Function &F) const { hash_map::const_iterator I = DSInfo.find(const_cast(&F)); assert(I != DSInfo.end() && "Function not in module!"); return *I->second; } DSGraph &getGlobalsGraph() const { return *GlobalsGraph; } EquivalenceClasses &getGlobalECs() { return GlobalECs; } /// print - Print out the analysis results... /// void print(std::ostream &O, const Module *M) const; /// releaseMemory - if the pass pipeline is done with this pass, we can /// release our memory... /// virtual void releaseMemory(); /// getAnalysisUsage - This obviously provides a data structure graph. /// virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); } }; /// BUDataStructures - The analysis that computes the interprocedurally closed /// data structure graphs for all of the functions in the program. This pass /// only performs a "Bottom Up" propagation (hence the name). /// class BUDataStructures : public ModulePass { protected: // DSInfo, one graph for each function hash_map DSInfo; DSGraph *GlobalsGraph; std::set > ActualCallees; // This map is only maintained during construction of BU Graphs std::map, std::pair > > *IndCallGraphMap; /// GlobalECs - The equivalence classes for each global value that is merged /// with other global values in the DSGraphs. EquivalenceClasses GlobalECs; public: ~BUDataStructures() { releaseMyMemory(); } virtual bool runOnModule(Module &M); bool hasGraph(const Function &F) const { return DSInfo.find(const_cast(&F)) != DSInfo.end(); } /// getDSGraph - Return the data structure graph for the specified function. /// DSGraph &getDSGraph(const Function &F) const { hash_map::const_iterator I = DSInfo.find(const_cast(&F)); if (I != DSInfo.end()) return *I->second; return const_cast(this)-> CreateGraphForExternalFunction(F); } DSGraph &getGlobalsGraph() const { return *GlobalsGraph; } EquivalenceClasses &getGlobalECs() { return GlobalECs; } DSGraph &CreateGraphForExternalFunction(const Function &F); /// deleteValue/copyValue - Interfaces to update the DSGraphs in the program. /// These correspond to the interfaces defined in the AliasAnalysis class. void deleteValue(Value *V); void copyValue(Value *From, Value *To); /// print - Print out the analysis results... /// void print(std::ostream &O, const Module *M) const; // FIXME: Once the pass manager is straightened out, rename this to // releaseMemory. void releaseMyMemory(); virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); } typedef std::set > ActualCalleesTy; const ActualCalleesTy &getActualCallees() const { return ActualCallees; } typedef ActualCalleesTy::const_iterator callee_iterator; callee_iterator callee_begin(Instruction *I) const { return ActualCallees.lower_bound(std::pair(I, 0)); } callee_iterator callee_end(Instruction *I) const { I = (Instruction*)((char*)I + 1); return ActualCallees.lower_bound(std::pair(I, 0)); } private: void calculateGraph(DSGraph &G); DSGraph &getOrCreateGraph(Function *F); unsigned calculateGraphs(Function *F, std::vector &Stack, unsigned &NextID, hash_map &ValMap); }; /// TDDataStructures - Analysis that computes new data structure graphs /// for each function using the closed graphs for the callers computed /// by the bottom-up pass. /// class TDDataStructures : public ModulePass { // DSInfo, one graph for each function hash_map DSInfo; hash_set ArgsRemainIncomplete; DSGraph *GlobalsGraph; BUDataStructures *BUInfo; /// GlobalECs - The equivalence classes for each global value that is merged /// with other global values in the DSGraphs. EquivalenceClasses GlobalECs; /// CallerCallEdges - For a particular graph, we keep a list of these records /// which indicates which graphs call this function and from where. struct CallerCallEdge { DSGraph *CallerGraph; // The graph of the caller function. const DSCallSite *CS; // The actual call site. Function *CalledFunction; // The actual function being called. CallerCallEdge(DSGraph *G, const DSCallSite *cs, Function *CF) : CallerGraph(G), CS(cs), CalledFunction(CF) {} bool operator<(const CallerCallEdge &RHS) const { return CallerGraph < RHS.CallerGraph || (CallerGraph == RHS.CallerGraph && CS < RHS.CS); } }; std::map > CallerEdges; // IndCallMap - We memoize the results of indirect call inlining operations // that have multiple targets here to avoid N*M inlining. The key to the map // is a sorted set of callee functions, the value is the DSGraph that holds // all of the caller graphs merged together, and the DSCallSite to merge with // the arguments for each function. std::map, DSGraph*> IndCallMap; public: ~TDDataStructures() { releaseMyMemory(); } virtual bool runOnModule(Module &M); bool hasGraph(const Function &F) const { return DSInfo.find(const_cast(&F)) != DSInfo.end(); } /// getDSGraph - Return the data structure graph for the specified function. /// DSGraph &getDSGraph(const Function &F) const { hash_map::const_iterator I = DSInfo.find(const_cast(&F)); if (I != DSInfo.end()) return *I->second; return const_cast(this)-> getOrCreateDSGraph(const_cast(F)); } DSGraph &getGlobalsGraph() const { return *GlobalsGraph; } EquivalenceClasses &getGlobalECs() { return GlobalECs; } /// deleteValue/copyValue - Interfaces to update the DSGraphs in the program. /// These correspond to the interfaces defined in the AliasAnalysis class. void deleteValue(Value *V); void copyValue(Value *From, Value *To); /// print - Print out the analysis results... /// void print(std::ostream &O, const Module *M) const; /// If the pass pipeline is done with this pass, we can release our memory... /// virtual void releaseMyMemory(); /// getAnalysisUsage - This obviously provides a data structure graph. /// virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); } private: void markReachableFunctionsExternallyAccessible(DSNode *N, hash_set &Visited); void InlineCallersIntoGraph(DSGraph &G); DSGraph &getOrCreateDSGraph(Function &F); void ComputePostOrder(Function &F, hash_set &Visited, std::vector &PostOrder); }; /// CompleteBUDataStructures - This is the exact same as the bottom-up graphs, /// but we use take a completed call graph and inline all indirect callees into /// their callers graphs, making the result more useful for things like pool /// allocation. /// struct CompleteBUDataStructures : public BUDataStructures { virtual bool runOnModule(Module &M); bool hasGraph(const Function &F) const { return DSInfo.find(const_cast(&F)) != DSInfo.end(); } /// getDSGraph - Return the data structure graph for the specified function. /// DSGraph &getDSGraph(const Function &F) const { hash_map::const_iterator I = DSInfo.find(const_cast(&F)); assert(I != DSInfo.end() && "Function not in module!"); return *I->second; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); // FIXME: TEMPORARY (remove once finalization of indirect call sites in the // globals graph has been implemented in the BU pass) AU.addRequired(); } /// print - Print out the analysis results... /// void print(std::ostream &O, const Module *M) const; private: unsigned calculateSCCGraphs(DSGraph &FG, std::vector &Stack, unsigned &NextID, hash_map &ValMap); DSGraph &getOrCreateGraph(Function &F); void processGraph(DSGraph &G); }; /// EquivClassGraphs - This is the same as the complete bottom-up graphs, but /// with functions partitioned into equivalence classes and a single merged /// DS graph for all functions in an equivalence class. After this merging, /// graphs are inlined bottom-up on the SCCs of the final (CBU) call graph. /// struct EquivClassGraphs : public ModulePass { CompleteBUDataStructures *CBU; DSGraph *GlobalsGraph; // DSInfo - one graph for each function. hash_map DSInfo; /// ActualCallees - The actual functions callable from indirect call sites. /// std::set > ActualCallees; // Equivalence class where functions that can potentially be called via the // same function pointer are in the same class. EquivalenceClasses FuncECs; /// OneCalledFunction - For each indirect call, we keep track of one /// target of the call. This is used to find equivalence class called by /// a call site. std::map OneCalledFunction; /// GlobalECs - The equivalence classes for each global value that is merged /// with other global values in the DSGraphs. EquivalenceClasses GlobalECs; public: /// EquivClassGraphs - Computes the equivalence classes and then the /// folded DS graphs for each class. /// virtual bool runOnModule(Module &M); /// print - Print out the analysis results... /// void print(std::ostream &O, const Module *M) const; EquivalenceClasses &getGlobalECs() { return GlobalECs; } /// getDSGraph - Return the data structure graph for the specified function. /// This returns the folded graph. The folded graph is the same as the CBU /// graph iff the function is in a singleton equivalence class AND all its /// callees also have the same folded graph as the CBU graph. /// DSGraph &getDSGraph(const Function &F) const { hash_map::const_iterator I = DSInfo.find(&F); assert(I != DSInfo.end() && "No graph computed for that function!"); return *I->second; } bool hasGraph(const Function &F) const { return DSInfo.find(&F) != DSInfo.end(); } /// ContainsDSGraphFor - Return true if we have a graph for the specified /// function. bool ContainsDSGraphFor(const Function &F) const { return DSInfo.find(&F) != DSInfo.end(); } /// getSomeCalleeForCallSite - Return any one callee function at /// a call site. /// Function *getSomeCalleeForCallSite(const CallSite &CS) const; DSGraph &getGlobalsGraph() const { return *GlobalsGraph; } typedef std::set > ActualCalleesTy; const ActualCalleesTy &getActualCallees() const { return ActualCallees; } typedef ActualCalleesTy::const_iterator callee_iterator; callee_iterator callee_begin(Instruction *I) const { return ActualCallees.lower_bound(std::pair(I, 0)); } callee_iterator callee_end(Instruction *I) const { I = (Instruction*)((char*)I + 1); return ActualCallees.lower_bound(std::pair(I, 0)); } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); } private: void buildIndirectFunctionSets(Module &M); unsigned processSCC(DSGraph &FG, std::vector &Stack, unsigned &NextID, std::map &ValMap); void processGraph(DSGraph &FG); DSGraph &getOrCreateGraph(Function &F); }; } // End llvm namespace #endif