From ad5a894df1841698c824381b414630799adc26ca Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Mon, 2 Aug 2010 23:46:59 +0000 Subject: [PATCH] Add 'AnalysisContext::getUnoptimizedCFG()' to allow clients to get access to the original CFG without any edges pruned out because of trivially solvable conditions (e.g., 'if (0)'). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110085 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Analysis/AnalysisContext.h | 12 ++++-- include/clang/Analysis/CFG.h | 1 + lib/Analysis/AnalysisContext.cpp | 14 ++++++- lib/Analysis/CFG.cpp | 53 +++++++++++++++--------- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 04672a5f18..169b1525d6 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -45,8 +45,8 @@ class AnalysisContext { idx::TranslationUnit *TU; // AnalysisContext owns the following data. - CFG *cfg; - bool builtCFG; + CFG *cfg, *completeCFG; + bool builtCFG, builtCompleteCFG; LiveVariables *liveness; ParentMap *PM; llvm::DenseMap *ReferencedBlockVars; @@ -55,7 +55,9 @@ class AnalysisContext { public: AnalysisContext(const Decl *d, idx::TranslationUnit *tu, bool addehedges = false) - : D(d), TU(tu), cfg(0), builtCFG(false), liveness(0), PM(0), + : D(d), TU(tu), cfg(0), completeCFG(0), + builtCFG(false), builtCompleteCFG(false), + liveness(0), PM(0), ReferencedBlockVars(0), AddEHEdges(addehedges) {} ~AnalysisContext(); @@ -72,6 +74,10 @@ public: bool getAddEHEdges() const { return AddEHEdges; } Stmt *getBody(); CFG *getCFG(); + + /// Return a version of the CFG without any edges pruned. + CFG *getUnoptimizedCFG(); + ParentMap &getParentMap(); LiveVariables *getLiveVariables(); diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index b7256c9dc3..b3bb8ae7df 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -285,6 +285,7 @@ public: /// 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 pruneTriviallyFalseEdges = true, bool AddEHEdges = false, bool AddScopes = false /* NOT FULLY IMPLEMENTED. NOT READY FOR GENERAL USE. */); diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 4a7c60d4cc..ef0a50f98e 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -55,7 +55,7 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { CFG *AnalysisContext::getCFG() { if (!builtCFG) { - cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges); + cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), true, AddEHEdges); // Even when the cfg is not successfully built, we don't // want to try building it again. builtCFG = true; @@ -63,6 +63,17 @@ CFG *AnalysisContext::getCFG() { return cfg; } +CFG *AnalysisContext::getUnoptimizedCFG() { + if (!builtCompleteCFG) { + completeCFG = CFG::buildCFG(D, getBody(), &D->getASTContext(), + false, AddEHEdges); + // Even when the cfg is not successfully built, we don't + // want to try building it again. + builtCompleteCFG = true; + } + return completeCFG; +} + ParentMap &AnalysisContext::getParentMap() { if (!PM) PM = new ParentMap(getBody()); @@ -297,6 +308,7 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) { AnalysisContext::~AnalysisContext() { delete cfg; + delete completeCFG; delete liveness; delete PM; delete ReferencedBlockVars; diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 08543aacba..821a578dbc 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -35,7 +35,7 @@ static SourceLocation GetEndLoc(Decl* D) { return D->getLocation(); } - + class AddStmtChoice { public: enum Kind { NotAlwaysAdd = 0, @@ -99,7 +99,8 @@ public: TryTerminatedBlock(NULL) {} // buildCFG - Used by external clients to construct the CFG. - CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges, + CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, + bool pruneTriviallyFalseEdges, bool AddEHEdges, bool AddScopes); private: @@ -174,12 +175,12 @@ private: CFGBlock *addStmt(Stmt *S) { return Visit(S, AddStmtChoice::AlwaysAdd); } - + void AppendStmt(CFGBlock *B, Stmt *S, AddStmtChoice asc = AddStmtChoice::AlwaysAdd) { B->appendStmt(S, cfg->getBumpVectorContext(), asc.asLValue()); } - + void AddSuccessor(CFGBlock *B, CFGBlock *S) { B->addSuccessor(S, cfg->getBumpVectorContext()); } @@ -206,6 +207,9 @@ private: /// TryEvaluateBool - Try and evaluate the Stmt and return 0 or 1 /// if we can evaluate to a known value, otherwise return -1. TryResult TryEvaluateBool(Expr *S) { + if (!PruneTriviallyFalseEdges) + return TryResult(); + Expr::EvalResult Result; if (!S->isTypeDependent() && !S->isValueDependent() && S->Evaluate(Result, *Context) && Result.Val.isInt()) @@ -216,6 +220,9 @@ private: bool badCFG; + // True iff trivially false edges should be pruned from the CFG. + bool PruneTriviallyFalseEdges; + // True iff EH edges on CallExprs should be added to the CFG. bool AddEHEdges; @@ -243,8 +250,12 @@ static VariableArrayType* FindVA(Type* t) { /// transferred to the caller. If CFG construction fails, this method returns /// NULL. CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C, + bool pruneTriviallyFalseEdges, bool addehedges, bool AddScopes) { + AddEHEdges = addehedges; + PruneTriviallyFalseEdges = pruneTriviallyFalseEdges; + Context = C; assert(cfg.get()); if (!Statement) @@ -384,10 +395,10 @@ tryAgain: case Stmt::CXXThrowExprClass: return VisitCXXThrowExpr(cast(S)); - + case Stmt::CXXTryStmtClass: return VisitCXXTryStmt(cast(S)); - + case Stmt::DeclStmtClass: return VisitDeclStmt(cast(S)); @@ -543,7 +554,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, autoCreateBlock(); AppendStmt(Block, B, asc); } - + Visit(B->getRHS()); return Visit(B->getLHS(), AddStmtChoice::AsLValueNotAlwaysAdd); } @@ -586,7 +597,7 @@ static bool CanThrow(Expr *E) { Ty = Ty->getAs()->getPointeeType(); else if (Ty->isBlockPointerType()) Ty = Ty->getAs()->getPointeeType(); - + const FunctionType *FT = Ty->getAs(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast(FT)) @@ -901,7 +912,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { // new blocks as the condition may contain control-flow. Any newly created // blocks will be pointed to be "Block". Block = addStmt(I->getCond()); - + // Finally, if the IfStmt contains a condition variable, add both the IfStmt // and the condition variable initialization to the CFG. if (VarDecl *VD = I->getConditionVariable()) { @@ -911,7 +922,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { addStmt(Init); } } - + return Block; } @@ -1029,7 +1040,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { assert(Block == EntryConditionBlock); } } - + if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1277,7 +1288,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); assert(Block == EntryConditionBlock); - + // If this block contains a condition variable, add both the condition // variable and initializer to the CFG. if (VarDecl *VD = W->getConditionVariable()) { @@ -1389,7 +1400,7 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { if (TryTerminatedBlock) // The current try statement is the only successor. AddSuccessor(Block, TryTerminatedBlock); - else + else // otherwise the Exit block is the only successor. AddSuccessor(Block, &cfg->getExit()); @@ -1589,7 +1600,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { assert(Terminator->getCond() && "switch condition must be non-NULL"); Block = SwitchTerminatedBlock; Block = addStmt(Terminator->getCond()); - + // Finally, if the SwitchStmt contains a condition variable, add both the // SwitchStmt and the condition variable initialization to the CFG. if (VarDecl *VD = Terminator->getConditionVariable()) { @@ -1599,7 +1610,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { addStmt(Init); } } - + return Block; } @@ -1742,9 +1753,9 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { return CatchBlock; } -CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, +CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc) { - AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue : AddStmtChoice::AlwaysAdd; autoCreateBlock(); AppendStmt(Block, C, AddStmtChoice(K)); @@ -1795,9 +1806,11 @@ CFGBlock* CFG::createBlock() { /// 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 PruneTriviallyFalse, bool AddEHEdges, bool AddScopes) { CFGBuilder Builder; - return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes); + return Builder.buildCFG(D, Statement, C, PruneTriviallyFalse, + AddEHEdges, AddScopes); } //===----------------------------------------------------------------------===// @@ -1814,10 +1827,10 @@ static void FindSubExprAssignments(Stmt *S, return; for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) { - Stmt *child = *I; + Stmt *child = *I; if (!child) continue; - + if (BinaryOperator* B = dyn_cast(child)) if (B->isAssignmentOp()) Set.insert(B); -- 2.40.0