Split tracking of unitialized values for Decls and CFGBlock-level expressions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42041 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Analysis/UnintializedValues.cpp b/Analysis/UnintializedValues.cpp
index dd741c1..c9c02d0 100644
--- a/Analysis/UnintializedValues.cpp
+++ b/Analysis/UnintializedValues.cpp
@@ -33,12 +33,12 @@
   
   void VisitVarDecl(VarDecl* D) {
     if (AD.VMap.find(D) == AD.VMap.end())
-      AD.VMap[D] = AD.Counter++;
+      AD.VMap[D] = AD.NumDecls++;
   }
   
   void BlockStmt_VisitExpr(Expr* E) {
     if (AD.EMap.find(E) == AD.EMap.end())
-      AD.EMap[E] = AD.Counter++;
+      AD.EMap[E] = AD.NumBlockExprs++;
   }        
 };
   
@@ -47,7 +47,9 @@
 void UninitializedValues::InitializeValues(const CFG& cfg) {
   RegisterDeclsAndExprs R(cfg,this->getAnalysisData());
   R.VisitAllDecls();    
-  getBlockDataMap()[ &cfg.getEntry() ].resize( getAnalysisData().Counter );
+  UninitializedValues::ValTy& V = getBlockDataMap()[&cfg.getEntry()];
+  V.DeclBV.resize(getAnalysisData().NumDecls);
+  V.ExprBV.resize(getAnalysisData().NumBlockExprs);
 }
 
 //===--------------------------------------------------------------------===//
@@ -55,44 +57,140 @@
 //===--------------------------------------------------------------------===//      
 
 namespace {
+
 class TransferFuncs : public CFGStmtVisitor<TransferFuncs,bool> {
   UninitializedValues::ValTy V;
   UninitializedValues::AnalysisDataTy& AD;
 public:
   TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {
-    V.resize(AD.Counter);
+    V.DeclBV.resize(AD.NumDecls);
+    V.ExprBV.resize(AD.NumBlockExprs);
   }
   
   UninitializedValues::ValTy& getVal() { return V; }
   
-//  bool VisitDeclRefExpr(DeclRefExpr* DR);
-//  bool VisitBinaryOperator(BinaryOperator* B);
-//  bool VisitUnaryOperator(UnaryOperator* U);    
+  bool VisitDeclRefExpr(DeclRefExpr* DR);
+  bool VisitBinaryOperator(BinaryOperator* B);
+  bool VisitUnaryOperator(UnaryOperator* U);
+  bool VisitStmt(Stmt* S);
+  bool VisitCallExpr(CallExpr* C);
+  bool BlockStmt_VisitExpr(Expr* E);
+  
+  static inline bool Initialized() { return true; }
+  static inline bool Unintialized() { return false; }
 };
+
+
+bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
+  if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
+    assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
+    return V.DeclBV[ AD.VMap[VD] ];    
+  }
+  else
+    return Initialized();
+}
+
+bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
+  if (CFG::hasImplicitControlFlow(B)) {
+    assert ( AD.EMap.find(B) != AD.EMap.end() && "Unknown block-level expr.");
+    return V.ExprBV[ AD.EMap[B] ];
+  }
+
+  return VisitStmt(B);
+}
+
+bool TransferFuncs::VisitCallExpr(CallExpr* C) {
+  VisitStmt(C);
+  return Initialized();
+}
+
+bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
+  switch (U->getOpcode()) {
+    case UnaryOperator::AddrOf: {
+      // Blast through parentheses and find the decl (if any).  Treat it
+      // as initialized from this point forward.
+      for (Stmt* S = U->getSubExpr() ;; )
+        if (ParenExpr* P = dyn_cast<ParenExpr>(S))
+          S = P->getSubExpr();
+        else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S)) {
+          if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
+            assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
+            V.DeclBV[ AD.VMap[VD] ] = Initialized();
+          }
+          break;
+        }
+        else {
+          // Evaluate the transfer function for subexpressions, even
+          // if we cannot reason more deeply about the &-expression.
+          return Visit(U->getSubExpr());
+        }
+
+      return Initialized();
+    }
+
+    default:
+      return Visit(U->getSubExpr());
+  }      
+}
+
+bool TransferFuncs::VisitStmt(Stmt* S) {
+  bool x = Initialized();
+
+  // We don't stop at the first subexpression that is Uninitialized because
+  // evaluating some subexpressions may result in propogating "Uninitialized"
+  // or "Initialized" to variables referenced in the other subexpressions.
+  for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
+    if (Visit(*I) == Unintialized())
+      x = Unintialized();
+  
+  return x;
+}
+
+bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
+  assert ( AD.EMap.find(E) != AD.EMap.end() );
+  return V.ExprBV[ AD.EMap[E] ] = Visit(E);
+}
+  
 } // end anonymous namespace
 
 //===--------------------------------------------------------------------===//
 // Merge operator.
+//
+//  In our transfer functions we take the approach that any
+//  combination of unintialized values, e.g. Unitialized + ___ = Unitialized.
+//
+//  Merges take the opposite approach.
+//
+//  In the merge of dataflow values (for Decls) we prefer unsoundness, and
+//  prefer false negatives to false positives.  At merges, if a value for a
+//  tracked Decl is EVER initialized in any of the predecessors we treat it as
+//  initialized at the confluence point.
+//
+//  For tracked CFGBlock-level expressions (such as the result of
+//  short-circuit), we do the opposite merge: if a value is EVER uninitialized
+//  in a predecessor we treat it as uninitalized at the confluence point.
+//  The reason we do this is because dataflow values for tracked Exprs are
+//  not as control-dependent as dataflow values for tracked Decls.
 //===--------------------------------------------------------------------===//      
 
 namespace {
 struct Merge {
   void operator()(UninitializedValues::ValTy& Dst,
                   UninitializedValues::ValTy& Src) {
-    assert (Dst.size() == Src.size() && "Bitvector sizes do not match.");
-    Src |= Dst;
+    assert (Dst.DeclBV.size() == Src.DeclBV.size() 
+            && "Bitvector sizes do not match.");
+            
+    Dst.DeclBV |= Src.DeclBV;
+    
+    assert (Dst.ExprBV.size() == Src.ExprBV.size()
+            && "Bitvector sizes do not match.");
+
+    Dst.ExprBV &= Src.ExprBV;
   }
 };
 } // end anonymous namespace
 
 //===--------------------------------------------------------------------===//
-// Observer to flag warnings for uses of uninitialized variables.
-//===--------------------------------------------------------------------===//      
-
-
-
-
-//===--------------------------------------------------------------------===//
 // External interface (driver logic).
 //===--------------------------------------------------------------------===//