[cfe-commits] r45552 - /cfe/trunk/Analysis/GRConstantPropagation.cpp

Ted Kremenek kremenek at apple.com
Thu Jan 3 14:12:29 PST 2008


Author: kremenek
Date: Thu Jan  3 16:12:28 2008
New Revision: 45552

URL: http://llvm.org/viewvc/llvm-project?rev=45552&view=rev
Log:
Initial checking of GRConstantPropagation.cpp, which implements a constant
propagation analysis via graph reachability. This analysis (which is incomplete)
will be the basis for later developments on the core engine for path-sensitive
analysis analysis.

Added:
    cfe/trunk/Analysis/GRConstantPropagation.cpp

Added: cfe/trunk/Analysis/GRConstantPropagation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/GRConstantPropagation.cpp?rev=45552&view=auto

==============================================================================
--- cfe/trunk/Analysis/GRConstantPropagation.cpp (added)
+++ cfe/trunk/Analysis/GRConstantPropagation.cpp Thu Jan  3 16:12:28 2008
@@ -0,0 +1,325 @@
+//===-- GRConstantPropagation.cpp --------------------------------*- C++ -*-==//
+//             
+//              [ Constant Propagation via Graph Reachability ]
+//   
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This files defines a simple analysis that performs path-sensitive
+//  constant propagation within a function.  An example use of this analysis
+//  is to perform simple checks for NULL dereferences.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/SimulGraph.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/CFG.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+using namespace clang;
+using llvm::APInt;
+using llvm::APFloat;
+using llvm::dyn_cast;
+using llvm::cast;
+
+//===----------------------------------------------------------------------===//
+// ConstV - Represents a variant over APInt, APFloat, and const char
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ConstV {
+  uintptr_t Data;
+public:
+  enum VariantType { VTString = 0x0, VTObjCString = 0x1,
+                     VTFloat  = 0x2, VTInt = 0x3,
+                     Flags    = 0x3 };
+  
+  ConstV(const StringLiteral* v) 
+    : Data(reinterpret_cast<uintptr_t>(v) | VTString) {}
+  
+  ConstV(const ObjCStringLiteral* v)
+    : Data(reinterpret_cast<uintptr_t>(v) | VTObjCString) {} 
+           
+  ConstV(llvm::APInt* v)
+    : Data(reinterpret_cast<uintptr_t>(v) | VTInt) {}
+  
+  ConstV(llvm::APFloat* v)
+    : Data(reinterpret_cast<uintptr_t>(v) | VTFloat) {}
+  
+
+  inline void* getData() const { return (void*) (Data & ~Flags); }
+  inline VariantType getVT() const { return (VariantType) (Data & Flags); } 
+  
+  inline void Profile(llvm::FoldingSetNodeID& ID) const {
+    ID.AddPointer(getData());
+  }
+};
+} // end anonymous namespace
+
+// Overload machinery for casting from ConstV to contained classes.
+
+namespace llvm {
+
+#define CV_OBJ_CAST(CLASS,FLAG)\
+template<> inline bool isa<CLASS,ConstV>(const ConstV& V) {\
+  return V.getVT() == FLAG;\
+}\
+\
+template <> struct cast_retty_impl<CLASS, ConstV> {\
+  typedef const CLASS* ret_type;\
+};
+  
+CV_OBJ_CAST(APInt,ConstV::VTInt)
+CV_OBJ_CAST(APFloat,ConstV::VTFloat)
+CV_OBJ_CAST(StringLiteral,ConstV::VTString)
+CV_OBJ_CAST(ObjCStringLiteral,ConstV::VTObjCString)  
+
+#undef CV_OBJ_CAST
+  
+template <> struct simplify_type<ConstV> {
+  typedef void* SimpleType;
+  static SimpleType getSimplifiedValue(const ConstV &Val) { 
+    return Val.getData();
+  }
+};
+
+} // end llvm namespace
+
+//===----------------------------------------------------------------------===//
+/// The checker.
+//===----------------------------------------------------------------------===//
+
+namespace {
+  
+  
+class GRCP {
+  
+  //==---------------------------------==//
+  //    Type definitions.
+  //==---------------------------------==//
+  
+public:
+  typedef llvm::ImmutableMap<Decl*,ConstV> StateTy;
+  typedef SimulVertex<StateTy> VertexTy;  
+  typedef SimulGraph<VertexTy> GraphTy;
+  typedef llvm::SmallVector<Stmt*,20> StmtStackTy;
+  typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
+  
+  /// DFSWorkList - A nested class that represents a worklist that processes
+  ///  vertices in LIFO order.
+  class DFSWorkList {
+    llvm::SmallVector<VertexTy*,20> Vertices;
+  public:
+    bool hasWork() const { return !Vertices.empty(); }
+    
+    /// Enqueue - Add a vertex to the worklist.
+    void Enqueue(VertexTy* V) { Vertices.push_back(V); }
+    
+    /// Dequeue - Remove a vertex from the worklist.
+    VertexTy* Dequeue() {
+      assert (hasWork());
+      VertexTy* V = Vertices.back();
+      Vertices.pop_back();
+      return V;
+    }
+  };
+  
+  //==---------------------------------==//
+  //    Data.
+  //==---------------------------------==//
+  
+private:
+  CFG& cfg;
+  
+  /// StateFactory - States are simply maps from Decls to constants.  This
+  ///  object is a collection of all the states (immutable maps) that are
+  ///  created by the analysis.  This object owns the created maps.
+  StateTy::Factory StateFactory;
+  
+  /// Graph - The simulation graph.  Each vertex is a (location,state) pair.
+  GraphTy Graph;
+  
+  /// ParentMap - A lazily populated map from a Stmt* to its parent Stmt*.
+  ParentMapTy ParentMap;
+  
+  /// StmtStack - A stack of statements/expressions that records the
+  ///  statement hierarchy starting from the Stmt* of the last dequeued
+  ///  vertex.  Used to lazily populate ParentMap.
+  StmtStackTy StmtStack;
+  
+  /// WorkList - A set of queued vertices that need to be processed by the
+  ///  worklist algorithm.
+  DFSWorkList WorkList;
+  
+  //==---------------------------------==//
+  //    Edge processing.
+  //==---------------------------------==//
+  
+  void MakeVertex(const ProgramEdge& Loc, StateTy State, VertexTy* PredV) {
+    std::pair<VertexTy*,bool> V = Graph.getVertex(Loc,State);
+    V.first->addPredecessor(PredV);
+    if (V.second) WorkList.Enqueue(V.first);
+  }
+  
+  void MakeVertex(const ProgramEdge& Loc, VertexTy* PredV) {
+    MakeVertex(Loc,PredV->getState(),PredV);
+  }
+  
+  void VisitBlkBlk(const BlkBlkEdge& E, VertexTy* PredV);
+  void VisitBlkStmt(const BlkStmtEdge& E, VertexTy* PredV);
+  void VisitStmtBlk(const StmtBlkEdge& E, VertexTy* PredV);
+  
+  void ProcessEOP(VertexTy* PredV);
+  void ProcessStmt(Stmt* S, VertexTy* PredV);
+  void ProcessTerminator(Stmt* Terminator ,VertexTy* PredV);
+
+  //==---------------------------------==//
+  //    Disable copying.
+  //==---------------------------------==//  
+  
+  GRCP(const GRCP&); // Do not implement.
+  GRCP& operator=(const GRCP&);
+
+  //==--------------------------------==//
+  //    Public API.
+  //==--------------------------------==//    
+  
+public:
+  GRCP(CFG& c);  
+  
+  /// getGraph - Returns the simulation graph.
+  const GraphTy& getGraph() const { return Graph; }
+  
+  /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
+  ///  steps.  Returns true if there is still simulation state on the worklist.
+  bool ExecuteWorkList(unsigned Steps = 1000000);  
+};
+} // end anonymous namespace
+
+
+//==--------------------------------------------------------==//
+//    Public API.
+//==--------------------------------------------------------==//
+
+GRCP::GRCP(CFG& c) : cfg(c) {
+  // Get the entry block.  Make sure that it has 1 (and only 1) successor.
+  CFGBlock* Entry = &c.getEntry();
+  
+  assert (Entry->empty() && "Entry block must be empty.");
+  assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
+  
+  // Get the first (and only) successor of Entry.
+  CFGBlock* Succ = *(Entry->succ_begin());
+  
+  // Construct an edge representing the starting location in the function.
+  BlkBlkEdge StartLoc(Entry,Succ);
+  
+  // Get the vertex.  Make it a root in the graph.
+  VertexTy* Root = Graph.getVertex(StartLoc,StateFactory.GetEmptyMap()).first;
+  Graph.addRoot(Root);
+  
+  // Enqueue the root so that it can be processed by the worklist.
+  WorkList.Enqueue(Root);
+}
+
+
+bool GRCP::ExecuteWorkList(unsigned Steps) {
+  while (Steps && WorkList.hasWork()) {
+    --Steps;
+    VertexTy* V = WorkList.Dequeue();
+    
+    // Dispatch on the location type.
+    switch (V->getLocation().getKind()) {
+      case ProgramEdge::BlkBlk:
+        VisitBlkBlk(cast<BlkBlkEdge>(V->getLocation()),V);
+        break;
+      
+      case ProgramEdge::BlkStmt:
+        VisitBlkStmt(cast<BlkStmtEdge>(V->getLocation()),V);
+        break;
+        
+      case ProgramEdge::StmtBlk:
+        VisitStmtBlk(cast<StmtBlkEdge>(V->getLocation()),V);
+        break;
+        
+      default:
+        assert (false && "Unsupported edge type.");
+    }
+  }
+  
+  return WorkList.hasWork();
+}
+
+//==--------------------------------------------------------==//
+//    Edge processing.
+//==--------------------------------------------------------==//
+
+void GRCP::VisitBlkBlk(const BlkBlkEdge& E, GRCP::VertexTy* PredV) {
+  
+  const CFGBlock* Blk = E.Dst();
+  
+  // FIXME: we will dispatch to a function that manipulates the state
+  //  at the entrance to a block.
+  
+  if (!Blk->empty()) {
+    // If 'Blk' has at least one statement, create a BlkStmtEdge and create
+    // the appropriate vertex.  This is the common case.
+    MakeVertex(BlkStmtEdge(Blk,Blk->front()), PredV->getState(), PredV);
+  }
+  else {
+    // Otherwise, create a vertex at the BlkStmtEdge right before the terminator
+    // (if any) is evaluated.  
+    MakeVertex(StmtBlkEdge(NULL,Blk),PredV->getState(), PredV);
+  }
+}
+
+void GRCP::VisitBlkStmt(const BlkStmtEdge& E, GRCP::VertexTy* PredV) {
+
+  // Check if we are entering the EXIT block.
+  if (E.Src() == &cfg.getExit()) {
+    assert (cfg.getExit().size() == 0 && "EXIT block cannot contain Stmts.");
+    // Process the End-Of-Path.
+    ProcessEOP(PredV);
+    return;
+  }
+
+  // Normal block.  Process as usual.  
+  if (Stmt* S = E.Dst())
+    ProcessStmt(S,PredV);
+  else {
+    // No statement.  Create an edge right before the terminator is evaluated.
+    MakeVertex(StmtBlkEdge(NULL,E.Src()), PredV->getState(), PredV);
+  }
+}
+  
+void GRCP::VisitStmtBlk(const StmtBlkEdge& E, GRCP::VertexTy* PredV) {
+  CFGBlock* Blk = E.Dst();
+  
+  if (Stmt* Terminator = Blk->getTerminator())
+    ProcessTerminator(Terminator,PredV);
+  else {
+    // No terminator.  We should have only 1 successor.
+    assert (Blk->succ_size() == 1);    
+    MakeVertex(BlkBlkEdge(Blk,*(Blk->succ_begin())), PredV);
+  }
+}
+
+void GRCP::ProcessEOP(GRCP::VertexTy* PredV) {
+  assert(false && "Not implemented.");
+}
+
+void GRCP::ProcessStmt(Stmt* S, GRCP::VertexTy* PredV) {
+  assert(false && "Not implemented.");
+}
+
+void GRCP::ProcessTerminator(Stmt* Terminator,GRCP::VertexTy* PredV) {
+  assert(false && "Not implemented.");  
+}





More information about the cfe-commits mailing list