CFG objects now internally store a (lazily created) map from block-level
expressions to IDs.  This is used by various dataflow analyses, but is
also useful for anyone querying a CFG to determine where an expression
is evaluated.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42495 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/AST/CFG.cpp b/AST/CFG.cpp
index acda71e..3755fa6 100644
--- a/AST/CFG.cpp
+++ b/AST/CFG.cpp
@@ -315,7 +315,7 @@
         Block->appendStmt(B);
         addStmt(B->getRHS());
         return addStmt(B->getLHS());
-      }    
+      }
 
       // Fall through to the default case.
     }
@@ -929,7 +929,55 @@
 /// reverseStmts - Reverses the orders of statements within a CFGBlock.
 void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); }
 
+//===----------------------------------------------------------------------===//
+// CFG: Queries for BlkExprs.
+//===----------------------------------------------------------------------===//
 
+namespace {
+  typedef llvm::DenseMap<const Expr*,unsigned> BlkExprMapTy;
+}
+
+static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
+  BlkExprMapTy* M = new BlkExprMapTy();
+  
+  for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
+    for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
+      if (const Expr* E = dyn_cast<Expr>(*BI))
+        (*M)[E] = M->size();
+  
+  return M;
+}
+
+bool CFG::isBlkExpr(const Stmt* S) {
+  if (const Expr* E = dyn_cast<Expr>(S)) return getBlkExprNum(E);
+  else return true;  // Statements are by default "block-level expressions."
+}
+
+CFG::BlkExprNumTy CFG::getBlkExprNum(const Expr* E) {
+  if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
+  
+  BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
+  BlkExprMapTy::iterator I = M->find(E);
+  
+  if (I == M->end()) return CFG::BlkExprNumTy();
+  else return CFG::BlkExprNumTy(I->second);
+}
+
+unsigned CFG::getNumBlkExprs() {
+  if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap))
+    return M->size();
+  else {
+    // We assume callers interested in the number of BlkExprs will want
+    // the map constructed if it doesn't already exist.
+    BlkExprMap = (void*) PopulateBlkExprMap(*this);
+    return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size();
+  }
+}
+
+CFG::~CFG() {
+  delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
+}
+  
 //===----------------------------------------------------------------------===//
 // CFG pretty printing
 //===----------------------------------------------------------------------===//
diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h
index e50c3cc..113ee87 100644
--- a/include/clang/AST/CFG.h
+++ b/include/clang/AST/CFG.h
@@ -23,6 +23,7 @@
 namespace clang {
 
   class Stmt;
+  class Expr;
   class CFG;
   class PrinterHelper;
   
@@ -263,6 +264,19 @@
   // CFG Introspection.
   //===--------------------------------------------------------------------===//
 
+  struct   BlkExprNumTy {
+    const signed Idx;
+    explicit BlkExprNumTy(signed idx) : Idx(idx) {}
+    explicit BlkExprNumTy() : Idx(-1) {}
+    operator bool() const { return Idx >= 0; }
+    operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
+  };
+    
+  bool          isBlkExpr(const Stmt* S);
+  bool          isBlkExpr(const Expr* E) { return getBlkExprNum(E); }
+  BlkExprNumTy  getBlkExprNum(const Expr* E);
+  unsigned      getNumBlkExprs();
+  
   unsigned getNumBlockIDs() const { return NumBlockIDs; }
 
   //===--------------------------------------------------------------------===//
@@ -277,8 +291,10 @@
   // Internal: constructors and data.
   //===--------------------------------------------------------------------===//
 
-  CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0) {};
-  ~CFG() {};
+  CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0), 
+          BlkExprMap(NULL) {};
+  
+  ~CFG();
     
 private:
   CFGBlock* Entry;
@@ -286,7 +302,10 @@
   CFGBlock* IndirectGotoBlock;  // Special block to contain collective dispatch
   // for indirect gotos
   CFGBlockListTy Blocks;
-  unsigned NumBlockIDs;
+  unsigned  NumBlockIDs;
+  // opaque pointer to prevent inclusion of DenseMap.h.  Map from expressions
+  // to integers to record block-level expressions.
+  void*     BlkExprMap;
 };
 } // end namespace clang