[cfe-commits] r94074 - in /cfe/trunk: include/clang/Analysis/CFG.h include/clang/Analysis/PathSensitive/AnalysisContext.h lib/Analysis/AnalysisContext.cpp lib/Analysis/CFG.cpp lib/Sema/SemaChecking.cpp lib/Sema/SemaDecl.cpp test/SemaCXX/warn-unreachable.cpp

Mike Stump mrs at apple.com
Thu Jan 21 07:20:48 PST 2010


Author: mrs
Date: Thu Jan 21 09:20:48 2010
New Revision: 94074

URL: http://llvm.org/viewvc/llvm-project?rev=94074&view=rev
Log:
Speed up compilation by avoiding generating exceptional edges from
CallExprs as those edges help cause a n^2 explosion in the number of
destructor calls.  Other consumers, such as static analysis, that
would like to have more a more complete CFG can select the inclusion
of those edges as CFG build time.

This also fixes up the two compilation users of CFGs to be tolerant of
having or not having those edges.  All catch code is assumed be to
live if we didn't generate the exceptional edges for CallExprs.

Added:
    cfe/trunk/test/SemaCXX/warn-unreachable.cpp
Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/include/clang/Analysis/PathSensitive/AnalysisContext.h
    cfe/trunk/lib/Analysis/AnalysisContext.cpp
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=94074&r1=94073&r2=94074&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Thu Jan 21 09:20:48 2010
@@ -133,7 +133,7 @@
 
   /// Label - An (optional) label that prefixes the executable
   ///  statements in the block.  When this variable is non-NULL, it is
-  ///  either an instance of LabelStmt or SwitchCase.
+  ///  either an instance of LabelStmt, SwitchCase or CXXCatchStmt.
   Stmt *Label;
 
   /// Terminator - The terminator for a basic block that
@@ -287,6 +287,7 @@
   /// buildCFG - Builds a CFG from an AST.  The responsibility to free the
   ///   constructed CFG belongs to the caller.
   static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C,
+                       bool AddEHEdges = false,
                        bool AddScopes = false);
 
   /// createBlock - Create a new block in the CFG.  The CFG owns the block;

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/AnalysisContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/AnalysisContext.h?rev=94074&r1=94073&r2=94074&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/AnalysisContext.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/AnalysisContext.h Thu Jan 21 09:20:48 2010
@@ -46,14 +46,21 @@
   ParentMap *PM;
   llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
   llvm::BumpPtrAllocator A;
+  bool AddEHEdges;
 public:
-  AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0),
-    ReferencedBlockVars(0) {}
+  AnalysisContext(const Decl *d, bool addehedges = false)
+    : D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0),
+      AddEHEdges(addehedges) {}
 
   ~AnalysisContext();
 
   ASTContext &getASTContext() { return D->getASTContext(); }
   const Decl *getDecl() { return D; }
+  /// getAddEHEdges - Return true iff we are adding exceptional edges from
+  /// callExprs.  If this is false, then try/catch statements and blocks
+  /// reachable from them can appear to be dead in the CFG, analysis passes must
+  /// cope with that.
+  bool getAddEHEdges() const { return AddEHEdges; }
   Stmt *getBody();
   CFG *getCFG();
   ParentMap &getParentMap();

Modified: cfe/trunk/lib/Analysis/AnalysisContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisContext.cpp?rev=94074&r1=94073&r2=94074&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/AnalysisContext.cpp (original)
+++ cfe/trunk/lib/Analysis/AnalysisContext.cpp Thu Jan 21 09:20:48 2010
@@ -55,7 +55,7 @@
 
 CFG *AnalysisContext::getCFG() {
   if (!cfg)
-    cfg = CFG::buildCFG(D, getBody(), &D->getASTContext());
+    cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges);
   return cfg;
 }
 

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=94074&r1=94073&r2=94074&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Thu Jan 21 09:20:48 2010
@@ -94,7 +94,8 @@
                           TryTerminatedBlock(NULL) {}
 
   // buildCFG - Used by external clients to construct the CFG.
-  CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddScopes);
+  CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges,
+                bool AddScopes);
 
 private:
   // Visitors to walk an AST and construct the CFG.
@@ -208,6 +209,11 @@
   }
 
   bool badCFG;
+
+  // True iff EH edges on CallExprs should be added to the CFG.
+  bool AddEHEdges;
+
+  // True iff scope start and scope end notes should be added to the CFG.
   bool AddScopes;
 };
 
@@ -231,7 +237,7 @@
 ///  transferred to the caller.  If CFG construction fails, this method returns
 ///  NULL.
 CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
-                          bool AddScopes) {
+                          bool AddEHEdges, bool AddScopes) {
   Context = C;
   assert(cfg.get());
   if (!Statement)
@@ -540,6 +546,22 @@
   return Block;
 }
 
+static bool CanThrow(Expr *E) {
+  QualType Ty = E->getType();
+  if (Ty->isFunctionPointerType())
+    Ty = Ty->getAs<PointerType>()->getPointeeType();
+  else if (Ty->isBlockPointerType())
+    Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
+    
+  const FunctionType *FT = Ty->getAs<FunctionType>();
+  if (FT) {
+    if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
+      if (Proto->hasEmptyExceptionSpec())
+        return false;
+  }
+  return true;
+}
+
 CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
   // If this is a call to a no-return function, this stops the block here.
   bool NoReturn = false;
@@ -547,21 +569,25 @@
     NoReturn = true;
   }
 
-  bool CanThrow = false;
+  bool AddEHEdge = false;
 
   // Languages without exceptions are assumed to not throw.
   if (Context->getLangOptions().Exceptions) {
-    CanThrow = true;
+    if (AddEHEdges)
+      AddEHEdge = true;
   }
 
   if (FunctionDecl *FD = C->getDirectCallee()) {
     if (FD->hasAttr<NoReturnAttr>())
       NoReturn = true;
     if (FD->hasAttr<NoThrowAttr>())
-      CanThrow = false;
+      AddEHEdge = false;
   }
 
-  if (!NoReturn && !CanThrow)
+  if (!CanThrow(C->getCallee()))
+    AddEHEdge = false;
+
+  if (!NoReturn && !AddEHEdge)
     return VisitStmt(C, asc);
 
   if (Block) {
@@ -577,7 +603,7 @@
     // Wire this to the exit block directly.
     AddSuccessor(Block, &cfg->getExit());
   }
-  if (CanThrow) {
+  if (AddEHEdge) {
     // Add exceptional edges.
     if (TryTerminatedBlock)
       AddSuccessor(Block, TryTerminatedBlock);
@@ -1714,9 +1740,9 @@
 /// buildCFG - Constructs a CFG from an AST.  Ownership of the returned
 ///  CFG is returned to the caller.
 CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C,
-                   bool AddScopes) {
+                   bool AddEHEdges, bool AddScopes) {
   CFGBuilder Builder;
-  return Builder.buildCFG(D, Statement, C, AddScopes);
+  return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes);
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=94074&r1=94073&r2=94074&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Jan 21 09:20:48 2010
@@ -2091,6 +2091,9 @@
     }
     return b[1].getStmt()->getLocStart();
   }
+  case Stmt::CXXTryStmtClass: {
+    return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
+  }
   default: ;
   }
   return S->getLocStart();
@@ -2167,12 +2170,20 @@
     return;
 
   llvm::SmallVector<SourceLocation, 24> lines;
+  bool AddEHEdges = AC.getAddEHEdges();
   // First, give warnings for blocks with no predecessors, as they
   // can't be part of a loop.
   for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
     CFGBlock &b = **I;
     if (!live[b.getBlockID()]) {
       if (b.pred_begin() == b.pred_end()) {
+        if (!AddEHEdges && b.getTerminator()
+            && isa<CXXTryStmt>(b.getTerminator())) {
+          // When not adding EH edges from calls, catch clauses
+          // can otherwise seem dead.  Avoid noting them as dead.
+          count += MarkLive(&b, live);
+          continue;
+        }
         SourceLocation c = GetUnreachableLoc(b);
         if (!c.isValid()) {
           // Blocks without a location can't produce a warning, so don't mark
@@ -2222,11 +2233,29 @@
     // FIXME: This should be NeverFallThrough
     return NeverFallThroughOrReturn;
 
-  // The CFG leaves in dead things, and we don't want to dead code paths to
+  // The CFG leaves in dead things, and we don't want the dead code paths to
   // confuse us, so we mark all live things first.
   std::queue<CFGBlock*> workq;
   llvm::BitVector live(cfg->getNumBlockIDs());
-  MarkLive(&cfg->getEntry(), live);
+  unsigned count = MarkLive(&cfg->getEntry(), live);
+
+  bool AddEHEdges = AC.getAddEHEdges();
+  if (!AddEHEdges && count != cfg->getNumBlockIDs())
+    // When there are things remaining dead, and we didn't add EH edges
+    // from CallExprs to the catch clauses, we have to go back and
+    // mark them as live.
+    for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+      CFGBlock &b = **I;
+      if (!live[b.getBlockID()]) {
+        if (b.pred_begin() == b.pred_end()) {
+          if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
+            // When not adding EH edges from calls, catch clauses
+            // can otherwise seem dead.  Avoid noting them as dead.
+            count += MarkLive(&b, live);
+          continue;
+        }
+      }
+    }
 
   // Now we know what is live, we check the live precessors of the exit block
   // and look for fall through paths, being careful to ignore normal returns,
@@ -2243,6 +2272,11 @@
     if (!live[B.getBlockID()])
       continue;
     if (B.size() == 0) {
+      if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
+        HasAbnormalEdge = true;
+        continue;
+      }
+
       // A labeled empty statement, or the entry block...
       HasPlainEdge = true;
       continue;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=94074&r1=94073&r2=94074&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 21 09:20:48 2010
@@ -4102,7 +4102,9 @@
   Decl *dcl = D.getAs<Decl>();
   Stmt *Body = BodyArg.takeAs<Stmt>();
 
-  AnalysisContext AC(dcl);
+  // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
+  // explosion for destrutors that can result and the compile time hit.
+  AnalysisContext AC(dcl, false);
   FunctionDecl *FD = 0;
   FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
   if (FunTmpl)

Added: cfe/trunk/test/SemaCXX/warn-unreachable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unreachable.cpp?rev=94074&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/warn-unreachable.cpp (added)
+++ cfe/trunk/test/SemaCXX/warn-unreachable.cpp Thu Jan 21 09:20:48 2010
@@ -0,0 +1,35 @@
+// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value
+
+int live();
+int dead();
+int liveti() throw(int);
+int (*livetip)() throw(int);
+
+int test1() {
+  try {
+    live();
+  } catch (int i) {
+    live();
+  }
+  return 1;
+}
+
+void test2() {
+  try {
+    live();
+  } catch (int i) {
+    live();
+  }
+  try {
+    liveti();
+  } catch (int i) {
+    live();
+  }
+  try {
+    livetip();
+  } catch (int i) {
+    live();
+  }
+  throw 1;
+  dead();       // expected-warning {{will never be executed}}
+}





More information about the cfe-commits mailing list