]> granicus.if.org Git - clang/commitdiff
Modified the notion of "Block-level expressions" in CFGs to include Stmt*. This
authorTed Kremenek <kremenek@apple.com>
Thu, 17 Jan 2008 20:48:37 +0000 (20:48 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 17 Jan 2008 20:48:37 +0000 (20:48 +0000)
is because GNU-style Statement-expressions cause the last statement in the
statement-expression to act like an expression.

We now have two notions: block-level statements and block-level expressions.

The former are all Stmt* that appear in the list of statements in CFGBlocks. The
latter is the subset of the former; these block-level statements are used as
subexpressions somewhere in the AST. CFG::isBlockExpr() returns true for the
latter, not the former (previously isBlockExpr() always returned true for
non-Expr Stmt*).

Modified the LiveVariables analysis to also track liveness state for block-level
expressions (using the updated definition of block-level expressions).

Modified the dataflow solver so that when it records values for block-level
statements, it records the dataflow value *before* the transfer function for a
Stmt* is evaluated (not after). This is more in sync in what clients will want.

Modified CFGStmtVisitor to record the current block-level statement.

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

AST/CFG.cpp
Analysis/LiveVariables.cpp
include/clang/AST/CFG.h
include/clang/Analysis/Analyses/LiveVariables.h
include/clang/Analysis/FlowSensitive/DataflowSolver.h
include/clang/Analysis/FlowSensitive/DataflowValues.h
include/clang/Analysis/Support/ExprDeclBitVector.h
include/clang/Analysis/Visitors/CFGStmtVisitor.h

index befd84020d059a43818ad3f887022171503acedb..7a13ac187a2ac08a45c8c48c1afa0db6c1bdf515 100644 (file)
@@ -988,7 +988,7 @@ void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); }
 //===----------------------------------------------------------------------===//
 
 namespace {
-  typedef llvm::DenseMap<const Expr*,unsigned> BlkExprMapTy;
+  typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
 }
 
 static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
@@ -999,23 +999,27 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
       if (const Expr* E = dyn_cast<Expr>(*BI)) {
         unsigned x = M->size();
         (*M)[E] = x;
+
+        // Special handling for statement expressions.  The last statement
+        // in the statement expression is also a block-level expr.
+        if (const StmtExpr* S = dyn_cast<StmtExpr>(E)) {
+          const CompoundStmt* C = S->getSubStmt();
+          if (!C->body_empty()) {
+            x = M->size();
+            (*M)[C->body_back()] = x;
+          }
+        }
       }
-  
-  return M;
-}
 
-bool CFG::isBlkExpr(const Stmt* S) {
-  assert (S != NULL);
-  if (const Expr* E = dyn_cast<Expr>(S)) return getBlkExprNum(E);
-  else return true;  // Statements are by default "block-level expressions."
+  return M;
 }
 
-CFG::BlkExprNumTy CFG::getBlkExprNum(const Expr* E) {
-  assert(E != NULL);
+CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) {
+  assert(S != NULL);
   if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
   
   BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
-  BlkExprMapTy::iterator I = M->find(E);
+  BlkExprMapTy::iterator I = M->find(S);
   
   if (I == M->end()) return CFG::BlkExprNumTy();
   else return CFG::BlkExprNumTy(I->second);
index ff4224a06fa2546883c5303ba71d088eca401850..5bd72b42af4232825d1f6453c8de911c8c7ff900 100644 (file)
@@ -77,7 +77,16 @@ void TransferFuncs::Visit(Stmt *S) {
   if (AD.Observer)
     AD.Observer->ObserveStmt(S,AD,LiveState);
   
-  static_cast<CFGStmtVisitor<TransferFuncs>*>(this)->Visit(S);
+
+  if (S == getCurrentBlkStmt()) {
+    StmtVisitor<TransferFuncs,void>::Visit(S);
+    if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead;
+  }
+  else if (!getCFG().isBlkExpr(S))
+    StmtVisitor<TransferFuncs,void>::Visit(S);
+  else
+    // For block-level expressions, mark that they are live.
+    LiveState(S,AD) = Alive;
 }
 
 void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
@@ -186,6 +195,10 @@ bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
   return Live(D,getAnalysisData());
 }
 
+bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
+  return getStmtData(Loc)(StmtVal,getAnalysisData());
+}
+
 //===----------------------------------------------------------------------===//
 // printing liveness state for debugging
 //
index 90e1338643e10656ec8a17cf26df5eaa6c4e983d..95f9cfdb8cc60900709b51199224003ad37e2c41 100644 (file)
@@ -255,9 +255,8 @@ public:
     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);
+  bool          isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
+  BlkExprNumTy  getBlkExprNum(const Stmt* S);
   unsigned      getNumBlkExprs();
   
   unsigned getNumBlockIDs() const { return NumBlockIDs; }
index 9f536988a9a1084d8f9414bdfe61ee2616a4e024..19e8d80029924ba11885d7db2e79d8b153539a24 100644 (file)
@@ -30,11 +30,10 @@ struct LiveVariables_ValueTypes {
 
 
   // We need to keep track of both declarations and CFGBlock-level expressions,
-  // (so that we don't explore such expressions twice), but we only need
-  // liveness information for declarations (hence 
-  // ValTy = DeclBitVector_Types::ValTy instead of 
-  // ValTy = ExprDeclBitVector_Types::ValTy).
-
+  // (so that we don't explore such expressions twice).  We also want
+  // to compute liveness information for block-level expressions, since these
+  // act as "temporary" values.
+  
   struct AnalysisDataTy : public ExprDeclBitVector_Types::AnalysisDataTy {
     ObserverTy* Observer;
     
@@ -42,7 +41,7 @@ struct LiveVariables_ValueTypes {
   };
 
     // We only keep actual dataflow state for declarations.
-  typedef DeclBitVector_Types::ValTy ValTy;
+  typedef ExprDeclBitVector_Types::ValTy ValTy;
   
   //===-----------------------------------------------------===//
   // ObserverTy - Observer for uninitialized values queries.
@@ -76,6 +75,10 @@ public:
   ///  has been recorded at the statement level (see runOnAllBlocks), and
   ///  only returns liveness information for block-level expressions.
   bool isLive(const Stmt* S, const VarDecl* D) const;
+                                              
+  /// IsLive - Returns true the block-level expression "value" is live
+  ///  before the given block-level expression (see runOnAllBlocks).
+  bool isLive(const Stmt* Loc, const Stmt* StmtVal) const;
   
   /// IsLive - Return true if a variable is live according to the
   ///  provided livness bitvector.
index 02619f5496161d80bc332383ad328f0da0d1207e..24ef6bb0baff593e1302e45e4b11535bca646037 100644 (file)
@@ -236,8 +236,8 @@ private:
   /// ProcessBlock - Process the transfer functions for a given block.
   void ProcessBlock(const CFGBlock* B, bool recordStmtValues) {
     for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
-      TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
       if (recordStmtValues) D.getStmtDataMap()[*I] = TF.getVal();
+      TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
     }      
   }
 
index be0a96014935ea15cec24dbafcdf01f9b293dfca..d6427a5cab47471e7659599ac803ccae67ef3480 100644 (file)
@@ -110,9 +110,9 @@ public:
   
   /// getStmtData - Retrieves the dataflow values associated with a 
   ///  specified Stmt.  If the dataflow analysis is a forward analysis,
-  ///  this data corresponds to the point immediately after a Stmt. 
+  ///  this data corresponds to the point immediately before a Stmt. 
   ///  If the analysis is a backwards analysis, it is associated with
-  ///  the point before a Stmt.  This data is only computed for block-level
+  ///  the point after a Stmt.  This data is only computed for block-level
   ///  expressions, and only when requested when the analysis is executed.
   ValTy& getStmtData(const Stmt* S) {
     assert (StmtDataMap && "Dataflow values were not computed for statements.");
index 12b93f98e6e9e602aa1ab775df38f2fbd01f42a0..dc634df5edb073317e93243d30dd7ebcdecf94a2 100644 (file)
@@ -139,11 +139,11 @@ struct ExprDeclBitVector_Types {
     void setCFG(CFG* c) { cfg = c; }
     CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
     
-    bool isTracked(const Expr* E) { return cfg->isBlkExpr(E); }
+    bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
     using DeclBitVector_Types::AnalysisDataTy::isTracked;
 
-    unsigned getIdx(const Expr* E) const {
-      CFG::BlkExprNumTy I = cfg->getBlkExprNum(E);
+    unsigned getIdx(const Stmt* S) const {
+      CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
       assert(I && "expression not tracked for bitvector.");
       return I;
     }
@@ -187,12 +187,12 @@ struct ExprDeclBitVector_Types {
     }
         
     llvm::BitVector::reference
-    operator()(const Expr* E, const AnalysisDataTy& AD) {
-      return ExprBV[AD.getIdx(E)];      
+    operator()(const Stmt* S, const AnalysisDataTy& AD) {
+      return ExprBV[AD.getIdx(S)];      
     }    
     const llvm::BitVector::reference
-    operator()(const Expr* E, const AnalysisDataTy& AD) const {
-      return const_cast<ValTy&>(*this)(E,AD);
+    operator()(const Stmt* S, const AnalysisDataTy& AD) const {
+      return const_cast<ValTy&>(*this)(S,AD);
     }
     
     using DeclBitVector_Types::ValTy::operator();
index cca2f40db485f553c387f9b74a6813f0a361f167..3d55b9d4160430f6472acebcb14e2932f46192b2 100644 (file)
@@ -33,7 +33,7 @@ static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
 
 template <typename ImplClass, typename RetTy=void>
 class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
-  Stmt* CurrentBlkExpr;
+  Stmt* CurrentBlkStmt;
 
   struct NullifyStmt {
     Stmt*& S;  
@@ -42,11 +42,13 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
     ~NullifyStmt() { S = NULL; }
   };
   
-public:  
-  CFGStmtVisitor() : CurrentBlkExpr(NULL) {}  
+public:
+  CFGStmtVisitor() : CurrentBlkStmt(NULL) {}  
+  
+  Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
   
   RetTy Visit(Stmt* S) {
-    if (S == CurrentBlkExpr || 
+    if (S == CurrentBlkStmt || 
         !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
       return StmtVisitor<ImplClass,RetTy>::Visit(S);
     else
@@ -59,8 +61,8 @@ public:
   /// is no implementation provided for a BlockStmt_XXX method, we default
   /// to using StmtVisitor's Visit method.
   RetTy BlockStmt_Visit(Stmt* S) {
-    CurrentBlkExpr = S;
-    NullifyStmt cleanup(CurrentBlkExpr);
+    CurrentBlkStmt = S;
+    NullifyStmt cleanup(CurrentBlkStmt);
     
     switch (S->getStmtClass()) {
       DISPATCH_CASE(CallExpr)