diff options
-rw-r--r-- | Analysis/LiveVariables.cpp | 282 | ||||
-rw-r--r-- | Analysis/Makefile | 22 | ||||
-rw-r--r-- | Driver/ASTStreamers.cpp | 25 | ||||
-rw-r--r-- | Driver/ASTStreamers.h | 2 | ||||
-rw-r--r-- | Driver/Makefile | 2 | ||||
-rw-r--r-- | Driver/clang.cpp | 10 | ||||
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 23 | ||||
-rw-r--r-- | include/clang/Analysis/LiveVariables.h | 111 |
8 files changed, 474 insertions, 3 deletions
diff --git a/Analysis/LiveVariables.cpp b/Analysis/LiveVariables.cpp new file mode 100644 index 0000000000..83c9b98044 --- /dev/null +++ b/Analysis/LiveVariables.cpp @@ -0,0 +1,282 @@ +//==- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Ted Kremenek and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/LiveVariables.h" +#include "clang/AST/Expr.h" +#include "clang/AST/CFG.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Lex/IdentifierTable.h" +#include "llvm/ADT/SmallPtrSet.h" + +#include <iostream> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// RegisterDecls - Utility class to create VarInfo objects for all +// Decls referenced in a function. +// + +namespace { + +class RegisterDecls : public StmtVisitor<RegisterDecls,void> { + LiveVariables& L; + const CFG& cfg; +public: + RegisterDecls(LiveVariables& l, const CFG& c) + : L(l), cfg(c) {} + + void VisitStmt(Stmt* S); + void VisitDeclRefExpr(DeclRefExpr* DR); + void Register(Decl* D); + void RegisterUsedDecls(); +}; + +void RegisterDecls::VisitStmt(Stmt* S) { + for (Stmt::child_iterator I = S->child_begin(),E = S->child_end(); I != E;++I) + Visit(*I); +} + +void RegisterDecls::VisitDeclRefExpr(DeclRefExpr* DR) { + for (Decl* D = DR->getDecl() ; D != NULL ; D = D->getNextDeclarator()) + Register(D); +} + +void RegisterDecls::Register(Decl* D) { + LiveVariables::VPair& VP = L.getVarInfoMap()[const_cast<const Decl*>(D)]; + + VP.V.AliveBlocks.reserve(cfg.getNumBlockIDs()); + VP.Idx = L.getNumDecls()++; +} + +void RegisterDecls::RegisterUsedDecls() { + for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) + for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI) + Visit(const_cast<Stmt*>(*SI)); +} + + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// WorkList - Data structure representing the liveness algorithm worklist. +// + +namespace { + +class WorkListTy { + typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet; + BlockSet wlist; +public: + void enqueue(const CFGBlock* B) { wlist.insert(B); } + + const CFGBlock* dequeue() { + assert (!wlist.empty()); + const CFGBlock* B = *wlist.begin(); + wlist.erase(B); + return B; + } + + bool isEmpty() const { return wlist.empty(); } +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// TFuncs +// + +namespace { + +class LivenessTFuncs : public StmtVisitor<LivenessTFuncs,void> { + LiveVariables& L; + llvm::BitVector Live; + llvm::BitVector Killed; +public: + LivenessTFuncs(LiveVariables& l) : L(l) { + Live.resize(l.getNumDecls()); + Killed.resize(l.getNumDecls()); + } + + void VisitStmt(Stmt* S); + void VisitDeclRefExpr(DeclRefExpr* DR); + void VisitBinaryOperator(BinaryOperator* B); + void VisitAssign(BinaryOperator* B); + void VisitStmtExpr(StmtExpr* S); + + unsigned getIdx(const Decl* D) { + LiveVariables::VarInfoMap& V = L.getVarInfoMap(); + LiveVariables::VarInfoMap::iterator I = V.find(D); + assert (I != V.end()); + return I->second.Idx; + } + + bool ProcessBlock(const CFGBlock* B); + llvm::BitVector* getLiveness(const CFGBlock* B); + +}; + +void LivenessTFuncs::VisitStmt(Stmt* S) { + // Evaluate the transfer functions for all subexpressions. Note that + // each invocation of "Visit" will have a side-effect: "Liveness" and "Kills" + // will be updated. + for (Stmt::child_iterator I = S->child_begin(),E = S->child_end(); I != E;++I) + Visit(*I); +} + +void LivenessTFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { + // Register a use of the variable. + Live.set(getIdx(DR->getDecl())); +} + +void LivenessTFuncs::VisitStmtExpr(StmtExpr* S) { + // Do nothing. The substatements of S are segmented into separate + // statements in the CFG. +} + +void LivenessTFuncs::VisitBinaryOperator(BinaryOperator* B) { + switch (B->getOpcode()) { + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + case BinaryOperator::Comma: + // Do nothing. These operations are broken up into multiple + // statements in the CFG. All these expressions do is return + // the value of their subexpressions, but these expressions will + // be evalualated elsewhere in the CFG. + break; + + // FIXME: handle '++' and '--' + default: + if (B->isAssignmentOp()) VisitAssign(B); + else Visit(B); + } +} + + +void LivenessTFuncs::VisitAssign(BinaryOperator* B) { + Stmt* LHS = B->getLHS(); + + if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) { + unsigned i = getIdx(DR->getDecl()); + Live.reset(i); + Killed.set(i); + } + else Visit(LHS); + + Visit(B->getRHS()); +} + + +llvm::BitVector* LivenessTFuncs::getLiveness(const CFGBlock* B) { + LiveVariables::BlockLivenessMap& BMap = L.getLiveAtBlockEntryMap(); + + LiveVariables::BlockLivenessMap::iterator I = BMap.find(B); + return (I == BMap.end()) ? NULL : &(I->second); +} + +bool LivenessTFuncs::ProcessBlock(const CFGBlock* B) { + // First: merge all predecessors. + Live.reset(); + Killed.reset(); + + for (CFGBlock::const_succ_iterator I=B->succ_begin(),E=B->succ_end();I!=E;++I) + if (llvm::BitVector* V = getLiveness(*I)) + Live |= *V; + + // Second: march up the statements and process the transfer functions. + for (CFGBlock::const_reverse_iterator I=B->rbegin(), E=B->rend(); I!=E; ++I) { + Visit(*I); + } + + // Third: compare the computed "Live" values with what we already have + // for this block. + bool hasChanged = false; + + LiveVariables::BlockLivenessMap& BMap = L.getLiveAtBlockEntryMap(); + LiveVariables::BlockLivenessMap::iterator I = BMap.find(B); + if (I == BMap.end()) { + hasChanged = true; + llvm::BitVector& V = BMap[B]; + V.resize(L.getNumDecls()); + V |= Live; + } + else if (I->second != Live) { + hasChanged = true; + I->second = Live; + } + + return hasChanged; +} + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// runOnCFG - Method to run the actual liveness computation. +// + +void LiveVariables::runOnCFG(const CFG& cfg) { + // Scan a CFG for DeclRefStmts. For each one, create a VarInfo object. + { + RegisterDecls R(*this,cfg); + R.RegisterUsedDecls(); + } + + // Create the worklist and enqueue the exit block. + WorkListTy WorkList; + WorkList.enqueue(&cfg.getExit()); + + // Create the state for transfer functions. + LivenessTFuncs TF(*this); + + // Process the worklist until it is empty. + + while (!WorkList.isEmpty()) { + const CFGBlock* B = WorkList.dequeue(); + if (TF.ProcessBlock(B)) + for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end(); + I != E; ++I) + WorkList.enqueue(*I); + } + + // Go through each block and reserve a bitvector. + for (CFG::const_iterator I = cfg.begin(), E = cfg.end(); I != E; ++I) + LiveAtBlockEntryMap[&(*I)].resize(NumDecls); +} + +//===----------------------------------------------------------------------===// +// printing liveness state for debugging +// + +void LiveVariables::printLiveness(const llvm::BitVector& V, + std::ostream& OS) const { + + for (VarInfoMap::iterator I = VarInfos.begin(), E=VarInfos.end(); I!=E; ++I) { + if (V[I->second.Idx]) { + OS << I->first->getIdentifier()->getName() << "\n"; + } + } +} + +void LiveVariables::printBlockLiveness(std::ostream& OS) const { + for (BlockLivenessMap::iterator I = LiveAtBlockEntryMap.begin(), + E = LiveAtBlockEntryMap.end(); + I != E; ++I) { + OS << "\n[ B" << I->first->getBlockID() + << " (live variables at block entry) ]\n"; + printLiveness(I->second, OS); + } +} + +void LiveVariables::DumpBlockLiveness() const { + printBlockLiveness(std::cerr); +}
\ No newline at end of file diff --git a/Analysis/Makefile b/Analysis/Makefile new file mode 100644 index 0000000000..eb47be8698 --- /dev/null +++ b/Analysis/Makefile @@ -0,0 +1,22 @@ +##===- clang/CodeGen/Makefile ------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file was developed by Ted Kremenek and is distributed under +# the University of Illinois Open Source License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements analyses built on top of source-level CFGs. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME := clangAnalysis +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../include + +include $(LEVEL)/Makefile.common + diff --git a/Driver/ASTStreamers.cpp b/Driver/ASTStreamers.cpp index f77505b9ee..a1494e4e1e 100644 --- a/Driver/ASTStreamers.cpp +++ b/Driver/ASTStreamers.cpp @@ -14,6 +14,7 @@ #include "ASTStreamers.h" #include "clang/AST/AST.h" #include "clang/AST/CFG.h" +#include "clang/Analysis/LiveVariables.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/ASTStreamer.h" using namespace clang; @@ -184,4 +185,28 @@ void clang::DumpCFGs(Preprocessor &PP, unsigned MainFileID, ASTStreamer_Terminate(Streamer); } +void clang::AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID) +{ + ASTContext Context(PP.getTargetInfo(), PP.getIdentifierTable()); + ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID); + + while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->getBody()) { + PrintFunctionDeclStart(FD); + fprintf(stderr,"\n"); + if (CFG* C = CFG::buildCFG(FD->getBody())) { + LiveVariables L; + L.runOnCFG(*C); + L.DumpBlockLiveness(); + } + else + fprintf(stderr," Error processing CFG.\n"); + } + } + } + + ASTStreamer_Terminate(Streamer); +} + diff --git a/Driver/ASTStreamers.h b/Driver/ASTStreamers.h index dfd9d54239..34ce8647b0 100644 --- a/Driver/ASTStreamers.h +++ b/Driver/ASTStreamers.h @@ -26,6 +26,8 @@ void DumpASTs(Preprocessor &PP, unsigned MainFileID, bool Stats); void DumpCFGs(Preprocessor &PP, unsigned MainFileID, bool Stats, bool use_graphviz = false); + +void AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID); } // end clang namespace diff --git a/Driver/Makefile b/Driver/Makefile index 4c9db0dc2d..eca316e204 100644 --- a/Driver/Makefile +++ b/Driver/Makefile @@ -3,6 +3,6 @@ CPPFLAGS += -I$(PROJ_SRC_DIR)/../include CXXFLAGS = -fno-rtti TOOLNAME = clang -USEDLIBS = clangCodeGen.a clangSEMA.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a +USEDLIBS = clangCodeGen.a clangSEMA.a clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a include $(LEVEL)/Makefile.common diff --git a/Driver/clang.cpp b/Driver/clang.cpp index 2bb4422b75..dde1c5737b 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -54,6 +54,7 @@ enum ProgActions { ParseAST, // Parse ASTs. ParseCFGDump, // Parse ASTS. Build CFGs. Print CFGs. ParseCFGView, // Parse ASTS. Build CFGs. View CFGs (Graphviz). + AnalysisLiveVariables, // Print results of live-variable analysis. ParsePrintCallbacks, // Parse and print each callback. ParseSyntaxOnly, // Parse and perform semantic analysis. ParseNoop, // Parse with noop callbacks. @@ -89,9 +90,11 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore, clEnumValN(ParseCFGDump, "dump-cfg", "Run parser, then build and print CFGs."), clEnumValN(ParseCFGView, "view-cfg", - "Run parser, then build and view CFGs with Graphviz."), + "Run parser, then build and view CFGs with Graphviz."), + clEnumValN(AnalysisLiveVariables, "dump-live-variables", + "Run parser and print results of live variable analysis."), clEnumValN(EmitLLVM, "emit-llvm", - "Build ASTs then convert to LLVM, emit .ll file"), + "Build ASTs then convert to LLVM, emit .ll file"), clEnumValEnd)); //===----------------------------------------------------------------------===// @@ -846,6 +849,9 @@ static void ProcessInputFile(Preprocessor &PP, unsigned MainFileID, case ParseCFGView: DumpCFGs(PP, MainFileID, Stats, true); break; + case AnalysisLiveVariables: + AnalyzeLiveVariables(PP, MainFileID); + break; case EmitLLVM: EmitLLVMFromASTs(PP, MainFileID, Stats); break; diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index ceddc1fe51..21ec8d128e 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; }; 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; }; 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; }; + 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; }; 84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; }; 84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; }; DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; }; @@ -209,6 +210,8 @@ 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; }; 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = "<group>"; }; 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; }; + 356EF9B20C8F7DBA006650F5 /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/LiveVariables.h; sourceTree = "<group>"; }; + 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = "<group>"; }; 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; }; 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = "<group>"; }; 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -361,6 +364,7 @@ DEC8D9920A9433F400353FCA /* AST */, DE67E7070C020EAB00F66BC5 /* Sema */, DE927FCC0C0557CD00231DA4 /* CodeGen */, + 356EF9B30C8F7DCA006650F5 /* Analysis */, ); name = Source; sourceTree = "<group>"; @@ -373,6 +377,22 @@ name = Products; sourceTree = "<group>"; }; + 356EF9AF0C8F7DA4006650F5 /* Analysis */ = { + isa = PBXGroup; + children = ( + 356EF9B20C8F7DBA006650F5 /* LiveVariables.h */, + ); + name = Analysis; + sourceTree = "<group>"; + }; + 356EF9B30C8F7DCA006650F5 /* Analysis */ = { + isa = PBXGroup; + children = ( + 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */, + ); + name = Analysis; + sourceTree = "<group>"; + }; C6859E8C029090F304C91782 /* Documentation */ = { isa = PBXGroup; children = ( @@ -539,6 +559,7 @@ DEC8D98B0A9433BC00353FCA /* AST */, DE67E7260C02108300F66BC5 /* Sema */, DE928B140C05659A00231DA4 /* CodeGen */, + 356EF9AF0C8F7DA4006650F5 /* Analysis */, ); path = include; sourceTree = "<group>"; @@ -637,6 +658,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; + compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; @@ -718,6 +740,7 @@ DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */, 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */, DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */, + 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/include/clang/Analysis/LiveVariables.h b/include/clang/Analysis/LiveVariables.h new file mode 100644 index 0000000000..38b992f8bb --- /dev/null +++ b/include/clang/Analysis/LiveVariables.h @@ -0,0 +1,111 @@ +//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Ted Kremenek and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIVEVARIABLES_H +#define LLVM_CLANG_LIVEVARIABLES_H + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include <iosfwd> +#include <vector> + +namespace clang { + + class Stmt; + class DeclRefStmt; + class Decl; + class CFG; + class CFGBlock; + +class LiveVariables { +public: + + struct VarInfo { + /// AliveBlocks - Set of blocks of which this value is alive completely + /// through. This is a bit set which uses the basic block number as an + /// index. + llvm::BitVector AliveBlocks; + + /// Kills - List of statements which are the last use of a variable + /// (kill it) in their basic block. The first pointer in the pair + /// is the statement in the list of statements of a basic block where + /// this occurs, while the DeclRefStmt is the subexpression of this + /// statement where the actual last reference takes place. + std::vector< std::pair<const Stmt*,const DeclRefStmt*> > Kills; + + void print(std::ostream& OS) const; + }; + + struct VPair { + VarInfo V; + unsigned Idx; + }; + + typedef llvm::DenseMap<const Decl*, VPair > VarInfoMap; + typedef llvm::DenseMap<const CFGBlock*, llvm::BitVector > BlockLivenessMap; + +public: + + LiveVariables() : NumDecls(0) {} + + /// runOnCFG - Computes live variable information for a given CFG. + void runOnCFG(const CFG& cfg); + + /// KillsVar - Return true if the specified statement kills the + /// specified variable. + bool KillsVar(const Stmt* S, const Decl* D) const; + + /// IsLive - Return true if a variable is live at beginning of a specified + // block. + bool IsLive(const CFGBlock* B, const Decl* D) const; + + /// getVarInfo - Return the liveness information associated with a given + /// variable. + VarInfo& getVarInfo(const Decl* D); + + const VarInfo& getVarInfo(const Decl* D) const; + + /// getVarInfoMap + VarInfoMap& getVarInfoMap() { return VarInfos; } + + const VarInfoMap& getVarInfoMap() const { return VarInfos; } + + // printLiveness + void printLiveness(const llvm::BitVector& V, std::ostream& OS) const; + + // printBlockLiveness + void printBlockLiveness(std::ostream& OS) const; + void DumpBlockLiveness() const; + + // getLiveAtBlockEntryMap + BlockLivenessMap& getLiveAtBlockEntryMap() { return LiveAtBlockEntryMap; } + + const BlockLivenessMap& getLiveAtBlockEntryMap() const { + return LiveAtBlockEntryMap; + } + + // getNumDecls + unsigned& getNumDecls() { return NumDecls; } + unsigned getNumDecls() const { return NumDecls; } + +protected: + + unsigned NumDecls; + VarInfoMap VarInfos; + BlockLivenessMap LiveAtBlockEntryMap; + +}; + +} // end namespace clang + +#endif |