]> granicus.if.org Git - clang/commitdiff
Added an early implementation of Live-Variables analysis built on
authorTed Kremenek <kremenek@apple.com>
Thu, 6 Sep 2007 00:17:54 +0000 (00:17 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 6 Sep 2007 00:17:54 +0000 (00:17 +0000)
source-level CFGs.  This code may change significantly in the near
future as we explore different means to implement dataflow analyses.

Added a driver option, -dump-live-variables, to view the output of
live variable analysis.  This output is very ALPHA; it will be improved shortly.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41737 91177308-0d34-0410-b5e6-96231b3b80d8

Analysis/LiveVariables.cpp [new file with mode: 0644]
Analysis/Makefile [new file with mode: 0644]
Driver/ASTStreamers.cpp
Driver/ASTStreamers.h
Driver/Makefile
Driver/clang.cpp
clang.xcodeproj/project.pbxproj
include/clang/Analysis/LiveVariables.h [new file with mode: 0644]

diff --git a/Analysis/LiveVariables.cpp b/Analysis/LiveVariables.cpp
new file mode 100644 (file)
index 0000000..83c9b98
--- /dev/null
@@ -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 (file)
index 0000000..eb47be8
--- /dev/null
@@ -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
+
index f77505b9ee8dfe02c02d1f47ca7d389a9761ed95..a1494e4e1e390d25fbdcbbc800828f4ac5431357 100644 (file)
@@ -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);
+}
+
 
index dfd9d542398918fd8003f113021d3077545283d4..34ce8647b0e1a41a8933fe5e7c88b36a2d6aa823 100644 (file)
@@ -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
 
index 4c9db0dc2d51c80f0b4f454f34442640c94b9f9e..eca316e2042cd7f24ea919e7a52bd13fae3dfe3b 100644 (file)
@@ -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
index 2bb4422b7583990730861d32055535939967e1dc..dde1c5737b3ea0d74e2255e6248a27ae0c3c255f 100644 (file)
@@ -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;
index ceddc1fe51371dbe08b56dff9d93b2afa896c564..21ec8d128e85683469aa0c4d9c565c4eae6588c9 100644 (file)
@@ -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 */; };
                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; };
                                DEC8D9920A9433F400353FCA /* AST */,
                                DE67E7070C020EAB00F66BC5 /* Sema */,
                                DE927FCC0C0557CD00231DA4 /* CodeGen */,
+                               356EF9B30C8F7DCA006650F5 /* Analysis */,
                        );
                        name = Source;
                        sourceTree = "<group>";
                        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 = (
                                DEC8D98B0A9433BC00353FCA /* AST */,
                                DE67E7260C02108300F66BC5 /* Sema */,
                                DE928B140C05659A00231DA4 /* CodeGen */,
+                               356EF9AF0C8F7DA4006650F5 /* Analysis */,
                        );
                        path = include;
                        sourceTree = "<group>";
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
                        projectDirPath = "";
                                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 (file)
index 0000000..38b992f
--- /dev/null
@@ -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