graphTemplate.h

Go to the documentation of this file.
00001 #ifndef BACKSTROKE_CFG_H
00002 #define BACKSTROKE_CFG_H
00003 
00004 
00005 #include <rose.h>
00006 #include <boost/graph/adjacency_list.hpp>
00007 #include <boost/bind.hpp>
00008 #include <boost/foreach.hpp>
00009 #include <boost/tuple/tuple.hpp>
00010 #include <boost/graph/graphviz.hpp>
00011 #include <boost/graph/dominator_tree.hpp>
00012 #include <boost/graph/reverse_graph.hpp>
00013 #include <boost/graph/transpose_graph.hpp>
00014 #include <boost/algorithm/string.hpp>
00015 
00016 
00017 namespace Backstroke
00018 {
00019 
00020 #define foreach BOOST_FOREACH
00021 
00022 
00024 template <class CFGNodeType>
00025 void writeCFGNode(std::ostream& out, const CFGNodeType& cfgNode)
00026 {
00027         SgNode* node = cfgNode.getNode();
00028         ROSE_ASSERT(node);
00029 
00030         std::string nodeColor = "black";
00031         if (isSgStatement(node))
00032                 nodeColor = "blue";
00033         else if (isSgExpression(node))
00034                 nodeColor = "green";
00035         else if (isSgInitializedName(node))
00036                 nodeColor = "red";
00037 
00038         std::string label;
00039 
00040         if (SgFunctionDefinition* funcDef = isSgFunctionDefinition(node))
00041         {
00042                 std::string funcName = funcDef->get_declaration()->get_name().str();
00043                 if (cfgNode.getIndex() == 0)
00044                         label = "Entry\\n" + funcName;
00045                 else if (cfgNode.getIndex() == 3)
00046                         label = "Exit\\n" + funcName;
00047         }
00048         
00049         if (!isSgScopeStatement(node) && !isSgCaseOptionStmt(node) && !isSgDefaultOptionStmt(node))
00050         {
00051                 std::string content = node->unparseToString();
00052                 boost::replace_all(content, "\"", "\\\"");
00053                 boost::replace_all(content, "\\n", "\\\\n");
00054                 label += content;
00055         }
00056     else
00057                 label += "<" + node->class_name() + ">";
00058     
00059     if (label == "")
00060                 label += "<" + node->class_name() + ">";
00061         
00062         out << "[label=\""  << label << "\", color=\"" << nodeColor <<
00063                 "\", style=\"" << (cfgNode.isInteresting()? "solid" : "dotted") << "\"]";
00064 }
00065 
00066 
00068 template <class CFGEdgeType>
00069 void writeCFGEdge(std::ostream& out, const CFGEdgeType& e)
00070 {
00071         out << "[label=\"" << escapeString(e.toString()) <<
00072                 "\", style=\"" << "solid" << "\"]";
00073 }
00074 
00075 
00076 // Predeclaration of class CFG.
00077 template <class CFGNodeFilter> class CFG;
00078 
00079 struct FullCFGNodeFilter
00080 {
00081         bool operator()(const VirtualCFG::CFGNode& cfgNode) const
00082         { return true; }
00083 };
00084 
00085 struct InterestingCFGNodeFilter
00086 {
00087         bool operator()(const VirtualCFG::CFGNode& cfgNode) const
00088         { return cfgNode.isInteresting(); }
00089 };
00090 
00092 typedef CFG<FullCFGNodeFilter> FullCFG;
00093 
00094 
00096 typedef CFG<InterestingCFGNodeFilter> FilteredCFG;
00097 
00098 
00099 
00100 
00101 
00102 /********************************************************************/
00103 //      The concept required to be fulfilled by CFGNodeFilter is
00104 //
00105 //      struct CFGNodeFilter
00106 //      {
00107 //              bool operator()(const VirtualCFG::CFGNode& cfgNode) const;
00108 //      };
00109 //
00110 /********************************************************************/
00111 
00113         
00114 template <class CFGNodeFilter>
00115 class CFG : public boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, 
00116                 boost::shared_ptr<VirtualCFG::FilteredCFGNode<CFGNodeFilter> >,
00117                 boost::shared_ptr<VirtualCFG::FilteredCFGEdge<CFGNodeFilter> > >
00118 {
00119         typedef typename boost::graph_traits<CFG<CFGNodeFilter> > GraphTraits;
00120 
00121 public:
00122     typedef VirtualCFG::FilteredCFGNode<CFGNodeFilter> CFGNodeType;
00123         typedef VirtualCFG::FilteredCFGEdge<CFGNodeFilter> CFGEdgeType;
00124 
00125         typedef boost::shared_ptr<CFGNodeType> CFGNodePtr;
00126         typedef boost::shared_ptr<CFGEdgeType> CFGEdgePtr;
00127 
00128     typedef typename GraphTraits::vertex_descriptor Vertex;
00129         typedef typename GraphTraits::edge_descriptor Edge;
00130 
00131         typedef std::map<Vertex, Vertex> VertexVertexMap;
00133         Vertex entry_;
00134 
00136         Vertex exit_;
00137 
00138 
00139 protected:
00140 
00142         SgFunctionDefinition* funcDef_;
00143 
00144 
00146         std::map<CFGNodeType, Vertex> nodesToVertices_;
00147 
00149     VertexVertexMap dominatorTree_;
00150 
00152     VertexVertexMap postdominatorTree_;
00153 
00154 public:
00155         std::map<CFGNodeType, Vertex> getNodeVert() {
00156             return nodesToVertices_;
00157         }
00158 
00160         CFG()
00161         :       funcDef_(NULL),
00162                 entry_(GraphTraits::null_vertex()),
00163                 exit_(GraphTraits::null_vertex())
00164         {
00165         }
00166 
00168         explicit CFG(SgFunctionDefinition* funcDef)
00169         :       funcDef_(funcDef),
00170                 entry_(GraphTraits::null_vertex()),
00171                 exit_(GraphTraits::null_vertex())
00172         {
00173                 build(funcDef);
00174         }
00175 
00177         void build(SgFunctionDefinition* funcDef);
00178 
00180         SgFunctionDefinition* getFunctionDefinition() const
00181         { return funcDef_; }
00182 
00184         const Vertex& getEntry() const
00185         { return entry_; }
00186 
00188         const Vertex& getExit() const
00189         { return exit_; }
00190 
00193         const VertexVertexMap& getDominatorTree();
00194 
00196         const VertexVertexMap& getPostdominatorTree();
00197 
00199         CFG<CFGNodeFilter> makeReverseCopy() const;
00200 
00202         void toDot(const std::string& filename) const;
00203 
00205         std::vector<CFGNodePtr> getAllNodes() const;
00206 
00208         std::vector<CFGEdgePtr> getAllEdges() const;
00209 
00212         Vertex getVertexForNode(const CFGNodeType &node) const;
00213 
00216     bool isReducible() const { return true; }
00217 
00219     std::vector<Edge> getAllBackEdges();
00220 
00222     std::vector<Vertex> getAllLoopHeaders();
00223 
00224 protected:
00225 
00227         void buildCFG(const CFGNodeType& node,
00228                         std::map<CFGNodeType, Vertex>& nodesAdded,
00229                         std::set<CFGNodeType>& nodesProcessed);
00230 
00232         void setEntryAndExit();
00233 
00235         void writeGraphNode(std::ostream& out, const Vertex& node) const
00236         {
00237                 writeCFGNode(out, *(*this)[node]);
00238                 //VirtualCFG::printNode(out, (*this)[node]);
00239         }
00240 
00242         void writeGraphEdge(std::ostream& out, const Edge& edge) const
00243         {
00244                 writeCFGEdge(out, *(*this)[edge]);
00245                 //VirtualCFG::printEdge(out, (*this)[edge], true);
00246         }
00247 
00249         struct VertexCopier
00250         {
00251                 VertexCopier(const CFG<CFGNodeFilter>& g1, CFG<CFGNodeFilter>& g2)
00252                 : cfg1(g1), cfg2(g2) {}
00253 
00254                 void operator()(const Vertex& v1, Vertex& v2) const
00255                 { cfg2[v2] = cfg1[v1]; }
00256                 
00257                 const CFG<CFGNodeFilter>& cfg1;
00258                 CFG<CFGNodeFilter>& cfg2;
00259         };
00260 
00262         struct EdgeCopier
00263         {
00264                 EdgeCopier(const CFG<CFGNodeFilter>& g1, CFG<CFGNodeFilter>& g2)
00265                 : cfg1(g1), cfg2(g2) {}
00266 
00267                 void operator()(const Edge& e1, Edge& e2) const
00268                 { cfg2[e2] = cfg1[e1]; }
00269 
00270                 const CFG<CFGNodeFilter>& cfg1;
00271                 CFG<CFGNodeFilter>& cfg2;
00272         };
00273 };
00274 
00275 
00276 
00277 template <class CFGNodeFilter>
00278 void CFG<CFGNodeFilter>::toDot(const std::string& filename) const
00279 {
00280         std::ofstream ofile(filename.c_str(), std::ios::out);
00281         boost::write_graphviz(ofile, *this,
00282                         boost::bind(&CFG<CFGNodeFilter>::writeGraphNode, this, ::_1, ::_2),
00283                         boost::bind(&CFG<CFGNodeFilter>::writeGraphEdge, this, ::_1, ::_2));
00284 }
00285 
00286 template <class CFGNodeFilter>
00287 void CFG<CFGNodeFilter>::build(SgFunctionDefinition* funcDef)
00288 {
00289         ROSE_ASSERT(funcDef);
00290         funcDef_ = funcDef;
00291 
00292         // The following two variables are used to record the nodes traversed.
00293         nodesToVertices_.clear();
00294         std::set<CFGNodeType> nodesProcessed;
00295 
00296         // Remove all nodes and edges first.
00297         this->clear();
00298         entry_ = GraphTraits::null_vertex();
00299         exit_ = GraphTraits::null_vertex();
00300 
00301         buildCFG(CFGNodeType(funcDef->cfgForBeginning()), nodesToVertices_, nodesProcessed);
00302 
00303         // Find the entry and exit of this CFG.
00304         setEntryAndExit();
00305 
00306         ROSE_ASSERT(isSgFunctionDefinition((*this)[entry_]->getNode()));
00307         ROSE_ASSERT(isSgFunctionDefinition((*this)[exit_]->getNode()));
00308 }
00309 
00310 template <class CFGNodeFilter>
00311 void CFG<CFGNodeFilter>::setEntryAndExit()
00312 {
00313     foreach (Vertex v, boost::vertices(*this))
00314         {
00315                 CFGNodePtr node = (*this)[v];
00316                 if (isSgFunctionDefinition(node->getNode()))
00317                 {
00318                         if (node->getIndex() == 0)
00319                                 entry_ = v;
00320                         else if (node->getIndex() == 3)
00321                                 exit_ = v;
00322                 }
00323         }
00324 
00325         //In graphs with an infinite loop, we might never get to the end vertex
00326         //In those cases, we need to add it explicitly
00327         if (exit_ == GraphTraits::null_vertex())
00328         {
00329                 std::cerr << "This function may contain an infinite loop "
00330                                 "inside so that its CFG cannot be built" << std::endl;
00331                 exit_ = add_vertex(*this);
00332                 (*this)[exit_] = CFGNodePtr(new CFGNodeType(funcDef_->cfgForEnd()));
00333         }
00334 
00335         ROSE_ASSERT(entry_ != GraphTraits::null_vertex());
00336         ROSE_ASSERT(exit_ != GraphTraits::null_vertex());
00337 }
00338 
00339 template <class CFGNodeFilter>
00340 void CFG<CFGNodeFilter>::buildCFG(
00341                 const CFGNodeType& node,
00342                 std::map<CFGNodeType, Vertex>& nodesAdded,
00343                 std::set<CFGNodeType>& nodesProcessed)
00344 {
00345         ROSE_ASSERT(node.getNode());
00346 
00347         if (nodesProcessed.count(node) > 0)
00348                 return;
00349         nodesProcessed.insert(node);
00350 
00351         typename std::map<CFGNodeType, Vertex>::iterator iter;
00352         bool inserted;
00353         Vertex from, to;
00354 
00355         // Add the source node.
00356         const CFGNodeType& src = node;
00357         ROSE_ASSERT(src.getNode());
00358 
00359         boost::tie(iter, inserted) = nodesAdded.insert(std::make_pair(src, Vertex()));
00360 
00361         if (inserted)
00362         {
00363                 from = add_vertex(*this);
00364                 (*this)[from] = CFGNodePtr(new CFGNodeType(src));
00365                 iter->second = from;
00366         }
00367         else
00368         {
00369                 from = iter->second;
00370         }
00371 
00372         std::vector<CFGEdgeType> outEdges = node.outEdges();
00373 
00374         foreach(const CFGEdgeType& cfgEdge, outEdges)
00375         {
00376                 // For each out edge, add the target node.
00377                 CFGNodeType tar = cfgEdge.target();
00378                 ROSE_ASSERT(tar.getNode());
00379 
00380                 boost::tie(iter, inserted) = nodesAdded.insert(std::make_pair(tar, Vertex()));
00381 
00382                 if (inserted)
00383                 {
00384                         to = add_vertex(*this);
00385                         (*this)[to] = CFGNodePtr(new CFGNodeType(tar));
00386                         iter->second = to;
00387                 }
00388                 else
00389                 {
00390                         to = iter->second;
00391                 }
00392 
00393                 // Add the edge.
00394                 Edge edge = add_edge(from, to, *this).first;
00395                 (*this)[edge] = CFGEdgePtr(new CFGEdgeType(cfgEdge));
00396 
00397                 // Build the CFG recursively.
00398                 buildCFG(tar, nodesAdded, nodesProcessed);
00399         }
00400 }
00401 
00402 template <class CFGNodeFilter>
00403 const typename CFG<CFGNodeFilter>::VertexVertexMap& CFG<CFGNodeFilter>::getDominatorTree()
00404 {
00405     if (!dominatorTree_.empty())
00406         return dominatorTree_;
00407 
00408         boost::associative_property_map<VertexVertexMap> domTreePredMap(dominatorTree_);
00409 
00410         // Here we use the algorithm in boost::graph to build a map from each node to its immediate dominator.
00411         boost::lengauer_tarjan_dominator_tree(*this, entry_, domTreePredMap);
00412         return dominatorTree_;
00413 }
00414 
00415 template <class CFGNodeFilter>
00416 const typename CFG<CFGNodeFilter>::VertexVertexMap& CFG<CFGNodeFilter>::getPostdominatorTree()
00417 {
00418     if (!postdominatorTree_.empty())
00419         return postdominatorTree_;
00420     
00421         boost::associative_property_map<VertexVertexMap> postdomTreePredMap(postdominatorTree_);
00422 
00423         // Here we use the algorithm in boost::graph to build an map from each node to its immediate dominator.
00424         boost::lengauer_tarjan_dominator_tree(boost::make_reverse_graph(*this), exit_, postdomTreePredMap);
00425         return postdominatorTree_;
00426 }
00427 
00428 template <class CFGNodeFilter>
00429 CFG<CFGNodeFilter> CFG<CFGNodeFilter>::makeReverseCopy() const
00430 {
00431         CFG<CFGNodeFilter> reverseCFG;
00432         // The following function makes a reverse CFG copy.
00433         boost::transpose_graph(*this, reverseCFG, 
00434                 boost::vertex_copy(VertexCopier(*this, reverseCFG)).
00435                 edge_copy(EdgeCopier(*this, reverseCFG)));
00436 
00437         // Swap entry and exit.
00438         reverseCFG.entry_ = this->exit_;
00439         reverseCFG.exit_ = this->entry_;
00440         return reverseCFG;
00441 }
00442 
00443 
00444 template <class CFGNodeFilter>
00445 std::vector<typename CFG<CFGNodeFilter>::CFGNodePtr>
00446 CFG<CFGNodeFilter>::getAllNodes() const
00447 {
00448         std::vector<CFGNodePtr> allNodes;
00449     foreach (Vertex v, boost::vertices(*this))
00450                 allNodes.push_back((*this)[v]);
00451         return allNodes;
00452 }
00453 
00454 /*
00455 template <class CFGNodeFilter>
00456 std::vector<typename CFG<CFGNodeFilter>::CFGNodeType>
00457 CFG<CFGNodeFilter>::getAllNodesNoPtrs() const
00458 {
00459         std::vector<CFGNodeType> allNodes;
00460     foreach (Vertex v, boost::vertices(*this))
00461                 allNodes.push_back(&((*this)[v]));
00462         return allNodes;
00463 }
00464 */
00465 
00466 template <class CFGNodeFilter>
00467 std::vector<typename CFG<CFGNodeFilter>::CFGEdgePtr>
00468 CFG<CFGNodeFilter>::getAllEdges() const
00469 {
00470         std::vector<CFGEdgePtr> allEdges;
00471     foreach (const Edge& e, boost::edges(*this))
00472                 allEdges.push_back((*this)[e]);
00473         return allEdges;
00474 }
00475 
00476 template <class CFGNodeFilter>
00477 typename CFG<CFGNodeFilter>::Vertex CFG<CFGNodeFilter>::getVertexForNode(const CFGNodeType &node) const
00478 {
00479         typename std::map<CFGNodeType, Vertex>::const_iterator vertexIter = nodesToVertices_.find(node);
00480         if (vertexIter == nodesToVertices_.end())
00481                 return GraphTraits::null_vertex();
00482         else
00483         {
00484                 ROSE_ASSERT(*(*this)[vertexIter->second] == node);
00485                 return vertexIter->second;
00486         }
00487 }
00488 
00489 template <class CFGNodeFilter>
00490 std::vector<typename CFG<CFGNodeFilter>::Edge> CFG<CFGNodeFilter>::getAllBackEdges()
00491 {
00492     std::vector<Edge> backEdges;
00493 
00494     // If the dominator tree is not built yet, build it now.
00495     getDominatorTree();
00496 
00497     foreach (const Edge& e, boost::edges(*this))
00498     {
00499         Vertex src = boost::source(e, *this);
00500         Vertex tar = boost::target(e, *this);
00501 
00502         //Vertex v = *(dominatorTree.find(src));
00503         typename VertexVertexMap::const_iterator iter = dominatorTree_.find(src);
00504         while (iter != dominatorTree_.end())
00505         {
00506             if (iter->second == tar)
00507             {
00508                 backEdges.push_back(e);
00509                 break; // break the while loop
00510             }
00511             iter = dominatorTree_.find(iter->second);
00512         }
00513     }
00514 
00515     return backEdges;
00516 }
00517 
00518 template <class CFGNodeFilter>
00519 std::vector<typename CFG<CFGNodeFilter>::Vertex> CFG<CFGNodeFilter>::getAllLoopHeaders()
00520 {
00521     std::vector<Edge> backEdges = getAllBackEdges();
00522     std::vector<Vertex> headers;
00523     foreach (Edge e, backEdges)
00524         headers.push_back(boost::target(e, *this));
00525     return headers;
00526 }
00527 
00528 #undef foreach
00529 
00530 } // End of namespace Backstroke
00531 
00532 
00533 #endif  /* BACKSTROKE_CFG_H */

Generated on Sat May 19 00:53:06 2012 for ROSE by  doxygen 1.4.7