[cfe-commits] r97122 - in /cfe/trunk: include/clang/Analysis/ProgramPoint.h include/clang/Checker/PathSensitive/Checker.h include/clang/Checker/PathSensitive/GRCoreEngine.h include/clang/Checker/PathSensitive/GRExprEngine.h include/clang/Checker/PathSensitive/GRSubEngine.h lib/Checker/CallInliner.cpp lib/Checker/GRCoreEngine.cpp lib/Checker/GRExprEngine.cpp

Zhongxing Xu xuzhongxing at gmail.com
Wed Feb 24 22:46:30 PST 2010


Author: zhongxingxu
Date: Thu Feb 25 00:46:30 2010
New Revision: 97122

URL: http://llvm.org/viewvc/llvm-project?rev=97122&view=rev
Log:
Call inliner improvements:

This patch implements the CallEnter/CallExit idea of Ted.

Add two interfaces to GRSubEngine: ProcessCallEnter, ProcessCallExit.

The CallEnter program point uses caller's location context. The
CallExit program point uses callee's location context.

CallEnter is built by GRStmtNodeBuilder. CallExit is built by
GREndPathNodeBuilder.

Modified:
    cfe/trunk/include/clang/Analysis/ProgramPoint.h
    cfe/trunk/include/clang/Checker/PathSensitive/Checker.h
    cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h
    cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
    cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h
    cfe/trunk/lib/Checker/CallInliner.cpp
    cfe/trunk/lib/Checker/GRCoreEngine.cpp
    cfe/trunk/lib/Checker/GRExprEngine.cpp

Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original)
+++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Thu Feb 25 00:46:30 2010
@@ -26,6 +26,7 @@
 namespace clang {
 
 class LocationContext;
+class FunctionDecl;
 
 class ProgramPoint {
 public:
@@ -41,6 +42,8 @@
               PostPurgeDeadSymbolsKind,
               PostStmtCustomKind,
               PostLValueKind,
+              CallEnterKind,
+              CallExitKind,
               MinPostStmtKind = PostStmtKind,
               MaxPostStmtKind = PostLValueKind };
 
@@ -308,6 +311,36 @@
   }
 };
 
+class CallEnter : public StmtPoint {
+public:
+  // CallEnter uses the caller's location context.
+  CallEnter(const Stmt *S, const FunctionDecl *fd, const LocationContext *L)
+    : StmtPoint(S, fd, CallEnterKind, L, 0) {}
+
+  const Stmt *getCallExpr() const {
+    return static_cast<const Stmt *>(getData1());
+  }
+
+  const FunctionDecl *getCallee() const {
+    return static_cast<const FunctionDecl *>(getData2());
+  }
+
+  static bool classof(const ProgramPoint *Location) {
+    return Location->getKind() == CallEnterKind;
+  }
+};
+
+class CallExit : public StmtPoint {
+public:
+  // CallExit uses the callee's location context.
+  CallExit(const Stmt *S, const LocationContext *L)
+    : StmtPoint(S, 0, CallExitKind, L, 0) {}
+
+  static bool classof(const ProgramPoint *Location) {
+    return Location->getKind() == CallExitKind;
+  }
+};
+
 
 } // end namespace clang
 

Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/Checker.h?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/Checker.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Thu Feb 25 00:46:30 2010
@@ -155,6 +155,14 @@
       Dst.Add(Pred);
   }
 
+  // Generate a node with a new program point different from the one that will
+  // be created by the GRStmtNodeBuilder.
+  void addTransition(const GRState *state, ProgramPoint Loc) {
+    ExplodedNode *N = B.generateNode(Loc, state, Pred);
+    if (N)
+      addTransition(N);
+  }
+
   void EmitReport(BugReport *R) {
     Eng.getBugReporter().EmitReport(R);
   }

Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h Thu Feb 25 00:46:30 2010
@@ -40,6 +40,8 @@
   friend class GRIndirectGotoNodeBuilder;
   friend class GRSwitchNodeBuilder;
   friend class GREndPathNodeBuilder;
+  friend class GRCallEnterNodeBuilder;
+  friend class GRCallExitNodeBuilder;
 
   GRSubEngine& SubEngine;
 
@@ -67,6 +69,9 @@
 
   void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
                     ExplodedNode* Pred);
+  void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
+                       unsigned Index, ExplodedNode *Pred);
+  void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
 
   /// Get the initial state from the subengine.
   const GRState* getInitialState(const LocationContext *InitLoc) {
@@ -90,6 +95,9 @@
 
   void ProcessSwitch(GRSwitchNodeBuilder& Builder);
 
+  void ProcessCallEnter(GRCallEnterNodeBuilder &Builder);
+  void ProcessCallExit(GRCallExitNodeBuilder &Builder);
+
 private:
   GRCoreEngine(const GRCoreEngine&); // Do not implement.
   GRCoreEngine& operator=(const GRCoreEngine&);
@@ -194,6 +202,12 @@
     return generateNode(S, St, Pred, PointKind);
   }
 
+  ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
+                             ExplodedNode* Pred) {
+    HasGeneratedNode = true;
+    return generateNodeInternal(PP, State, Pred);
+  }
+
   ExplodedNode*
   generateNodeInternal(const ProgramPoint &PP, const GRState* State,
                        ExplodedNode* Pred);
@@ -431,6 +445,8 @@
   ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
                              ExplodedNode *P = 0);
 
+  void GenerateCallExitNode(const GRState *state);
+
   CFGBlock* getBlock() const { return &B; }
 
   const GRState* getState() const {
@@ -438,6 +454,56 @@
   }
 };
 
+class GRCallEnterNodeBuilder {
+  GRCoreEngine &Eng;
+
+  const ExplodedNode *Pred;
+
+  // The call site.
+  const Stmt *CE;
+
+  // The definition of callee.
+  const FunctionDecl *FD;
+
+  // The parent block of the CallExpr.
+  const CFGBlock *Block;
+
+  // The CFGBlock index of the CallExpr.
+  unsigned Index;
+
+public:
+  GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred, 
+                         const Stmt *s, const FunctionDecl *fd, 
+                         const CFGBlock *blk, unsigned idx)
+    : Eng(eng), Pred(pred), CE(s), FD(fd), Block(blk), Index(idx) {}
+
+  const GRState *getState() const { return Pred->getState(); }
+
+  const LocationContext *getLocationContext() const { 
+    return Pred->getLocationContext();
+  }
+
+  const Stmt *getCallExpr() const { return CE; }
+
+  const FunctionDecl *getCallee() const { return FD; }
+
+  const CFGBlock *getBlock() const { return Block; }
+
+  unsigned getIndex() const { return Index; }
+
+  void GenerateNode(const GRState *state, const LocationContext *LocCtx);
+};
+
+class GRCallExitNodeBuilder {
+  GRCoreEngine &Eng;
+  const ExplodedNode *Pred;
+
+public:
+  GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred)
+    : Eng(eng), Pred(pred) {}
+
+  void GenerateNode();
+}; 
 } // end clang namespace
 
 #endif

Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Thu Feb 25 00:46:30 2010
@@ -171,7 +171,13 @@
   /// ProcessEndPath - Called by GRCoreEngine.  Used to generate end-of-path
   ///  nodes when the control reaches the end of a function.
   void ProcessEndPath(GREndPathNodeBuilder& builder);
-  
+
+  // Generate the entry node of the callee.
+  void ProcessCallEnter(GRCallEnterNodeBuilder &builder);
+
+  // Generate the first post callsite node.
+  void ProcessCallExit(GRCallExitNodeBuilder &builder);
+
   /// EvalAssume - Callback function invoked by the ConstraintManager when
   ///  making assumptions about state values.
   const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption);

Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h Thu Feb 25 00:46:30 2010
@@ -28,6 +28,8 @@
 class GRIndirectGotoNodeBuilder;
 class GRSwitchNodeBuilder;
 class GREndPathNodeBuilder;
+class GRCallEnterNodeBuilder;
+class GRCallExitNodeBuilder;
 class LocationContext;
 
 class GRSubEngine {
@@ -64,6 +66,12 @@
   /// ProcessEndPath - Called by GRCoreEngine.  Used to generate end-of-path
   ///  nodes when the control reaches the end of a function.
   virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0;
+
+  // Generate the entry node of the callee.
+  virtual void ProcessCallEnter(GRCallEnterNodeBuilder &builder) = 0;
+
+  // Generate the first post callsite node.
+  virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0;
   
   /// EvalAssume - Called by ConstraintManager. Used to call checker-specific
   ///  logic for handling assumptions on symbolic values.

Modified: cfe/trunk/lib/Checker/CallInliner.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallInliner.cpp?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/CallInliner.cpp (original)
+++ cfe/trunk/lib/Checker/CallInliner.cpp Thu Feb 25 00:46:30 2010
@@ -46,40 +46,9 @@
   if (!FD->isThisDeclarationADefinition())
     return false;
 
-  GRStmtNodeBuilder &Builder = C.getNodeBuilder();
-  // Make a new LocationContext.
-  const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, 
-                                   C.getPredecessor()->getLocationContext(), CE,
-                                   Builder.getBlock(), Builder.getIndex());
-
-  CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());
-
-  assert (Entry->empty() && "Entry block must be empty.");
-
-  assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
-
-  // Get the solitary successor.
-  CFGBlock const *SuccB = *(Entry->succ_begin());
-
-  // Construct an edge representing the starting location in the function.
-  BlockEdge Loc(Entry, SuccB, LocCtx);
-
-  state = C.getStoreManager().EnterStackFrame(state, LocCtx);
-
-  // This is a hack. We really should not use the GRStmtNodeBuilder.
-  bool isNew;
-  GRExprEngine &Eng = C.getEngine();
-  ExplodedNode *Pred = C.getPredecessor();
-  
-
-  ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
-  SuccN->addPredecessor(Pred, Eng.getGraph());
-  C.getNodeBuilder().Deferred.erase(Pred);
-  
-  if (isNew)
-    Builder.getWorkList()->Enqueue(SuccN);
-
-  Builder.HasGeneratedNode = true;
+  // Now we have the definition of the callee, create a CallEnter node.
+  CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext());
+  C.addTransition(state, Loc);
 
   return true;
 }
@@ -102,23 +71,9 @@
   SymbolReaper SymReaper(*ParentSF->getLiveVariables(), Eng.getSymbolManager(), 
                          ParentSF);
   const Stmt *CE = LocCtx->getCallSite();
-
+  // FIXME: move this logic to GRExprEngine::ProcessCallExit().
   state = Eng.getStateManager().RemoveDeadBindings(state, const_cast<Stmt*>(CE),
                                                    SymReaper);
 
-
-  PostStmt NodeLoc(CE, LocCtx->getParent());
-
-  bool isNew;
-  ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew);
-  Succ->addPredecessor(Pred, Eng.getGraph());
-
-  // When creating the new work list unit, increment the statement index to
-  // point to the statement after the CallExpr.
-  if (isNew)
-    B.getWorkList().Enqueue(Succ, 
-                            *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
-                            LocCtx->getIndex() + 1);
-
-  B.HasGeneratedNode = true;
+  B.GenerateCallExitNode(state);
 }

Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original)
+++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 00:46:30 2010
@@ -144,6 +144,14 @@
   SubEngine.ProcessSwitch(Builder);
 }
 
+void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) {
+  SubEngine.ProcessCallEnter(Builder);
+}
+
+void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) {
+  SubEngine.ProcessCallExit(Builder);
+}
+
 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
 bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
 
@@ -196,6 +204,15 @@
         assert (false && "BlockExit location never occur in forward analysis.");
         break;
 
+      case ProgramPoint::CallEnterKind:
+        HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(), 
+                        WU.getIndex(), Node);
+        break;
+
+      case ProgramPoint::CallExitKind:
+        HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
+        break;
+
       default:
         assert(isa<PostStmt>(Node->getLocation()));
         HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
@@ -207,6 +224,17 @@
   return WList->hasWork();
 }
 
+void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
+                                   unsigned Index, ExplodedNode *Pred) {
+  GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), 
+                                 Block, Index);
+  ProcessCallEnter(Builder);
+}
+
+void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
+  GRCallExitNodeBuilder Builder(*this, Pred);
+  ProcessCallExit(Builder);
+}
 
 void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
 
@@ -400,6 +428,12 @@
 void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
   assert (!N->isSink());
 
+  // Check if this node entered a callee.
+  if (isa<CallEnter>(N->getLocation())) {
+    Eng.WList->Enqueue(N, B, Idx); // Still use the index of the CallExpr.
+    return;
+  }
+
   PostStmt Loc(getStmt(), N->getLocationContext());
 
   if (Loc == N->getLocation()) {
@@ -597,3 +631,57 @@
 
   return NULL;
 }
+
+void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) {
+  HasGeneratedNode = true;
+  // Create a CallExit node and enqueue it.
+  const StackFrameContext *LocCtx
+                         = cast<StackFrameContext>(Pred->getLocationContext());
+  const Stmt *CE = LocCtx->getCallSite();
+
+  // Use the the callee location context.
+  CallExit Loc(CE, LocCtx);
+
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+  Node->addPredecessor(Pred, *Eng.G);
+
+  if (isNew)
+    Eng.WList->Enqueue(Node);
+}
+                                                
+
+void GRCallEnterNodeBuilder::GenerateNode(const GRState *state,
+                                          const LocationContext *LocCtx) {
+  // Get the callee entry block.
+  const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry());
+  assert(Entry->empty());
+  assert(Entry->succ_size() == 1);
+
+  // Get the solitary successor.
+  const CFGBlock *SuccB = *(Entry->succ_begin());
+
+  // Construct an edge representing the starting location in the callee.
+  BlockEdge Loc(Entry, SuccB, LocCtx);
+
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+  Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+
+  if (isNew)
+    Eng.WList->Enqueue(Node);
+}
+
+void GRCallExitNodeBuilder::GenerateNode() {
+  // Get the callee's location context.
+  const StackFrameContext *LocCtx 
+                         = cast<StackFrameContext>(Pred->getLocationContext());
+
+  PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, Pred->getState(), &isNew);
+  Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+  if (isNew)
+    Eng.WList->Enqueue(Node, *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
+                       LocCtx->getIndex() + 1);
+}

Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97122&r1=97121&r2=97122&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Checker/GRExprEngine.cpp Thu Feb 25 00:46:30 2010
@@ -1290,6 +1290,24 @@
   if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt);
 }
 
+void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) {
+  const FunctionDecl *FD = B.getCallee();
+  const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, 
+                                                       B.getLocationContext(),
+                                                       B.getCallExpr(),
+                                                       B.getBlock(),
+                                                       B.getIndex());
+
+  const GRState *state = B.getState();
+  state = getStoreManager().EnterStackFrame(state, LocCtx);
+
+  B.GenerateNode(state, LocCtx);
+}
+
+void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
+  B.GenerateNode();
+}
+
 //===----------------------------------------------------------------------===//
 // Transfer functions: logical operations ('&&', '||').
 //===----------------------------------------------------------------------===//
@@ -3141,6 +3159,14 @@
         assert (false);
         break;
 
+      case ProgramPoint::CallEnterKind:
+        Out << "CallEnter";
+        break;
+
+      case ProgramPoint::CallExitKind:
+        Out << "CallExit";
+        break;
+
       default: {
         if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
           const Stmt* S = L->getStmt();





More information about the cfe-commits mailing list