C-Breeze
C Compiler Infrastructure

[ Project home page]
Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

vcgCCG.cc

Go to the documentation of this file.
00001 // $Id: vcgCCG.cc,v 1.6 2003/08/11 19:05:01 toktb Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2003 University of Texas at Austin
00008 // 
00009 //  Samuel Z. Guyer
00010 //  Adam Brown
00011 //  Teck Bok Tok
00012 //  Paul Arthur Navratil
00013 //  Calvin Lin
00014 // 
00015 //  Permission is hereby granted, free of charge, to any person
00016 //  obtaining a copy of this software and associated documentation
00017 //  files (the "Software"), to deal in the Software without
00018 //  restriction, including without limitation the rights to use, copy,
00019 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00020 //  of the Software, and to permit persons to whom the Software is
00021 //  furnished to do so, subject to the following conditions:
00022 //  
00023 //  The above copyright notice and this permission notice shall be
00024 //  included in all copies or substantial portions of the Software.
00025 //  
00026 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00027 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00028 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00029 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00030 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00031 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00032 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00033 //  THE SOFTWARE.
00034 //
00035 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00036 //  Computer Science for inspiring parts of the C-Breeze design.
00037 //
00038 // ----------------------------------------------------------------------
00039 #include "vcg.h"
00040 #include "linker.h"
00041 
00042 // generate call graph
00043 class vcgCCGWalker: public vcgWalker {
00044 private:
00045   //typedef list<procNode*>            proc_list;
00046   typedef map <procNode*,node_list>  edge_map;
00047 
00048   proc_decl_map proc_map;
00049   node_list  nodes;
00050   procNode  *current_proc;
00051   string     current_proc_name; // the current calling context
00052   edge_map   edges;             // to avoid duplicate edges
00053 
00054   void at_proc( procNode *proc, Order ord ) {
00055     if(ord==Postorder) currently_excluded = false;
00056     else               currently_excluded = excluded(proc);
00057     if (ord == Postorder || currently_excluded) return;
00058     print_node(proc);
00059 
00060     declNode* decl = proc->decl();
00061     assert( decl );
00062     current_proc_name = decl->name();
00063     current_proc = proc;
00064   }
00065 
00066   void at_call( callNode *call, Order ord ) {
00067     // If the current procedure is requested to be excluded from the graph
00068     if (ord == Postorder || currently_excluded) return;
00069     if(call->proc())
00070       print_node(call->proc());
00071     else
00072       print_node(call);
00073     print_edge(current_proc, call->proc(), call);
00074   }
00075 
00076   void at_threeAddr(threeAddrNode *t, Order ord) {
00077     if (ord == Postorder || currently_excluded) return;
00078     if(t->rhs1() && t->rhs1()->var()->typ()==Id) {
00079       idNode *id = (idNode*) t->rhs1()->var();
00080       declNode *d = id->decl();
00081       if(d->type() && d->type()->typ() == Func) {
00082         procNode *p = proc_map[d];
00083         assert(p);
00084         print_edge(current_proc, p, id);
00085       }
00086     }
00087   }
00088 
00089   void print_node(procNode *n) {
00090     // has the node been printed?
00091     if(find(nodes.begin(), nodes.end(), n) != nodes.end()) return;
00092     if(n->typ()!=Unit && excluded(n->coord())) return;                          
00093 
00094     nodes.push_front(n);
00095 
00096     graph << endl;
00097     graph << "   node: {" << endl;
00098     print_node_attribute( "title", node_title(n));
00099     print_node_attribute( "label", node_label(n) );
00100     graph << "   }" << endl;
00101   } // print_node(proc)
00102 
00103   // used for unknown callee.
00104   // for different calls, only one is printed if they have same node_title
00105   void print_node(callNode *c) {
00106     if(excluded(c->coord())) return;                          
00107 
00108     // has the node been printed?
00109     string title = node_title(c);
00110     for(node_list_p n=nodes.begin(); n!=nodes.end(); n++)
00111       if(node_title(*n) == title) return;
00112 
00113     nodes.push_front(c);
00114 
00115     graph << endl;
00116     graph << "   node: {" << endl;
00117     print_node_attribute( "title", title);
00118     print_node_attribute( "label", node_label(c) );
00119     print_node_value( "shape", "ellipse" );
00120     graph << "   }" << endl;
00121   } // print_node(call)
00122 
00123   void print_edge(procNode *from, procNode *to, callNode *call) {
00124     node_list targets=edges[from];
00125     // has the edge been printed?
00126     if(to) {
00127       if(find(targets.begin(), targets.end(), to) != targets.end()) return;
00128       edges[from].push_front(to);
00129     } else {
00130       if(find(targets.begin(), targets.end(), call) != targets.end()) return;
00131       edges[from].push_front(call);
00132     }
00133 
00134     graph << endl;
00135     graph << "   edge: {";
00136     graph << "  sourcename: \"" << node_title(from) << "\"";
00137     if(to)
00138       graph << "  targetname: \"" << node_title(to)   << "\"";
00139     else
00140       graph << "  targetname: \"" << node_title(call)   << "\"";
00141     graph << "  label: \"" << call->coord().line()   << "\"";
00142     graph << "  }" << endl;
00143   } // print_edge
00144 
00145   // with new dismantler, the "call node" becomes just an idNode.
00146   void print_node(idNode *c) {
00147     if(excluded(c->coord())) return;                          
00148 
00149     // has the node been printed?
00150     string title = node_title(c);
00151     for(node_list_p n=nodes.begin(); n!=nodes.end(); n++)
00152       if(node_title(*n) == title) return;
00153 
00154     nodes.push_front(c);
00155 
00156     graph << endl;
00157     graph << "   node: {" << endl;
00158     print_node_attribute( "title", title);
00159     print_node_attribute( "label", node_label(c) );
00160     print_node_value( "shape", "ellipse" );
00161     graph << "   }" << endl;
00162   } // print_node(call)
00163 
00164   // with new dismantler, the "call node" becomes just an idNode.
00165   void print_edge(procNode *from, procNode *to, idNode *call) {
00166     node_list targets=edges[from];
00167     // has the edge been printed?
00168     if(to) {
00169       if(find(targets.begin(), targets.end(), to) != targets.end()) return;
00170       edges[from].push_front(to);
00171     } else {
00172       if(find(targets.begin(), targets.end(), call) != targets.end()) return;
00173       edges[from].push_front(call);
00174     }
00175 
00176     graph << endl;
00177     graph << "   edge: {";
00178     graph << "  sourcename: \"" << node_title(from) << "\"";
00179     if(to)
00180       graph << "  targetname: \"" << node_title(to)   << "\"";
00181     else
00182       graph << "  targetname: \"" << node_title(call)   << "\"";
00183     graph << "  label: \"" << call->coord().line()   << "\"";
00184     graph << "  }" << endl;
00185   } // print_edge
00186 
00187   string node_title(Node *n) {
00188     if(n->typ()==Call) return node_name(n);
00189     ostringstream title;
00190     char hex[16];
00191     sprintf(hex, "(%x)\0", n);
00192     title << node_name(n) << '@' << n->coord() << '.' << n->coord().offset()
00193           << hex << '\0';
00194     return title.str();
00195   } // node_title
00196  
00197   string node_label(Node *n) {
00198     if(n->typ()==Call) return node_name(n);
00199     ostringstream label;
00200     Coord coord = n->coord();
00201     label << node_name(n) << ':' << coord.line() << '.' << coord.offset()
00202           << '\0';
00203     return label.str();
00204   } // node_label
00205 
00206 #define STRING(s1,s2) (string(s1 + string(" `") + s2 + "'"))
00207 
00208   string node_name(Node *n) {
00209     if(!n) return string("");
00210     switch(n->typ()) {
00211       case Proc: return STRING("Proc", ((procNode*)n)->decl()->name());
00212       case Call: {
00213         callNode *call = (callNode*) n;
00214         exprNode *cname = call->name();
00215         switch(cname->typ()) {
00216           case Id: return STRING("Call", ((idNode*) cname)->name());
00217           case Ptr: return "Call <Ptr>";
00218           case Unary: {
00219             ostringstream name;
00220             name <<"Call <Unary "<< ((unaryNode*)cname)->op()->print() <<">\0";
00221             return name.str();
00222           }
00223           default: {
00224             ostringstream name;
00225             name << "Call <unknown " << cname->typ() << ">\0";
00226             return name.str();
00227           }
00228         }
00229       }
00230       default: assert(false);
00231     }
00232   } // node_name
00233 
00234 public:
00235   vcgCCGWalker(ostream& ostr, const string& comment, string excludefilename,
00236                proc_decl_map p)
00237     : vcgWalker(ostr,comment,excludefilename), current_proc(NULL), proc_map(p){
00238     nodes.clear();  
00239     // Start graph description
00240     print_comment();
00241     print_comment( "=== C-Breeze Call Graph visualization ===" );
00242     print_comment();
00243     if( !comment.empty() ) {
00244       print_comment( comment );
00245       print_comment();
00246     }
00247 
00248     start_graph();
00249     print_graph_attribute( "orientation", "left_to_right" );
00250     print_graph_attribute( "display_edge_labels", "yes" );
00251   } // vcgCGWalker
00252 
00253   virtual ~vcgCCGWalker(void) { }
00254 }; // class vcgCCGWalker
00255 
00256 
00257 // phase for generating call graph
00258 class vcgCCGPhase: public Phase {
00259 private:
00260   string excludefilename;
00261 public:
00262   vcgCCGPhase() {}
00263   virtual ~vcgCCGPhase() {}
00264   void run (void) {
00265     Linker L;
00266     L.link();
00267     proc_decl_map proc_map = L.procedures();
00268 
00269     string graph_file_name;
00270 
00271     if( CBZ::Program.empty() ) return;  // no units
00272     else if( CBZ::Program.size()==1 ) {
00273       // just one unit
00274        unitNode* u = CBZ::Program.front();
00275        graph_file_name = u->input_file() + ".callg";
00276     } else {
00277       cout << "Several compilation units present. Creating combined call graph."
00278            << endl;
00279       graph_file_name = "combined.callg";
00280     }
00281 
00282     // Open the output file.
00283     ofstream graph_file( graph_file_name.c_str() );
00284     
00285     if( graph_file ) {
00286       // Create the walker and process the ASTs of each unit.
00287       vcgCCGWalker callgw(graph_file, "File: " + graph_file_name,
00288                           excludefilename, L.procedures());
00289 
00290       for(unit_list_p i=CBZ::Program.begin(); i!=CBZ::Program.end(); ++i) {
00291         unitNode* u = *i;
00292         u->walk( callgw );  // build the graph
00293       }
00294 
00295     } else /* if( !graph_file ) */ {
00296       cerr << "vcgCGPhase: Can not open '" << graph_file_name
00297            << "' for writing." << endl;
00298     }
00299   }
00300 
00301   void get_flags(str_list_p & arg) { 
00302     string opt = *arg;
00303     if(strncmp("exclude:", opt.c_str(), 8) == 0) {
00304       excludefilename = opt;
00305       excludefilename.erase(0,8);
00306       arg++;
00307     }
00308   };
00309 }; // vcgCGPhase
00310 
00311 Phases vcgccgPhase( "vcgCCG", new vcgCCGPhase() );

Generated on August 27, 2003
Back to the C-Breeze home page