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  

callgraph.cc

Go to the documentation of this file.
00001 // $Id: callgraph.cc,v 1.4 2003/08/07 23:13:40 pnav Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2000 University of Texas at Austin
00008 // 
00009 //  Samuel Z. Guyer
00010 //  Daniel A. Jimenez
00011 //  Calvin Lin
00012 // 
00013 //  Permission is hereby granted, free of charge, to any person
00014 //  obtaining a copy of this software and associated documentation
00015 //  files (the "Software"), to deal in the Software without
00016 //  restriction, including without limitation the rights to use, copy,
00017 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00018 //  of the Software, and to permit persons to whom the Software is
00019 //  furnished to do so, subject to the following conditions:
00020 //  
00021 //  The above copyright notice and this permission notice shall be
00022 //  included in all copies or substantial portions of the Software.
00023 //  
00024 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00026 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00028 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00029 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00030 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00031 //  THE SOFTWARE.
00032 //
00033 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00034 //  Computer Science for inspiring parts of the C-Breeze design.
00035 //
00036 // ----------------------------------------------------------------------
00037 
00038 
00039 #include "c_breeze.h"
00040 #include "callgraph.h"
00041 
00042 callGraph::callGraph(procNode * root, Linker & linker)
00043   : Walker(Preorder, Subtree),
00044     _callgraph(),
00045     _root(root),
00046     _linker(linker),
00047     _current(0)
00048 {
00049   // Create entries for all procedure definitions
00050 
00051   const proc_decl_map & procs = linker.procedures();
00052   for (proc_decl_map_cp p = procs.begin();
00053        p != procs.end();
00054        ++p)
00055     {
00056       procNode * pr = (*p).second;
00057       _current = lookup(pr);
00058       pr->walk(*this);
00059     }
00060 }
00061 
00062 callGraph::~callGraph()
00063 {
00064   for (callgraph_map_p p = _callgraph.begin();
00065        p != _callgraph.end();
00066        ++p)
00067     delete (*p).second;
00068 }      
00069 
00070 void callGraph::at_id(idNode * the_id, Order ord)
00071 {
00072   if (! the_id->decl())
00073     cout << "ID with no decl: " << the_id->name() << endl;
00074   else 
00075     if (the_id->decl()->type()->typ() == Func) {
00076       procNode * proc = _linker.lookup_procedure(the_id->decl());
00077       if (proc) {
00078         callGraphNode * cgn = lookup(proc);
00079         // cout << _current->proc()->decl()->name() << " calls " << cgn->proc()->decl()->name() << endl;
00080         _current->add_edge(cgn);
00081       }
00082     }
00083 }
00084 
00085 callGraphNode * callGraph::lookup(procNode * proc)
00086 {
00087   callGraphNode * cgnode;
00088   callgraph_map_p p = _callgraph.find(proc);
00089   if (p == _callgraph.end()) {
00090     cgnode = new callGraphNode(proc);
00091     _callgraph[proc] = cgnode;
00092   }
00093   else
00094     cgnode = (*p).second;
00095 
00096   return cgnode;
00097 }
00098 
00099 void callGraph::show_all_contexts()
00100 {
00101   callgraph_edge_list stack;
00102   int count = 0;
00103   callGraphNode * start = lookup(_root);
00104   show_all_contexts(start, stack, count);
00105 
00106   cout << "Total procedures: " << _callgraph.size() << endl;
00107   cout << "Total contexts: " << count << endl;
00108 }
00109   
00110 void callGraph::show_all_contexts(callGraphNode * cur,
00111                                   callgraph_edge_list & stack,
00112                                   int & count)
00113 {
00114   callgraph_edge_list_p rec = find(stack.begin(), stack.end(), cur);
00115   if (rec != stack.end()) {
00116     // cout << "Recursion" << endl;
00117     return;
00118   }
00119 
00120   stack.push_back(cur);
00121   count++;
00122 
00123   /*
00124   for (callgraph_edge_list_p p = stack.begin();
00125        p != stack.end();
00126        ++p)
00127     {
00128       callGraphNode * cgn = *p;
00129       if (p != stack.begin())
00130         cout << ".";
00131       cout << cgn->proc()->decl()->name();
00132     }
00133   cout << endl;
00134   */
00135 
00136   for (callgraph_edge_list_cp p = cur->calls().begin();
00137        p != cur->calls().end();
00138        ++p)
00139     {
00140       callGraphNode * cgn = *p;
00141       show_all_contexts(cgn, stack, count);
00142     }
00143 
00144   stack.pop_back();
00145 }
00146 
00147 void callGraphNode::add_edge(callGraphNode * to)
00148 {
00149   _calls.push_back(to);
00150   to->_called_by.push_back(this);
00151 }
00152 
00153 int callGraphNode::times_called()
00154 {
00155   callgraph_node_set visited;
00156 
00157   return times_called(visited);
00158 }
00159 
00160 int callGraphNode::times_called(callgraph_node_set & visited)
00161 {
00162   int total = 0;
00163 
00164   if (visited.find(this) != visited.end())
00165     return _times_called;
00166 
00167   visited.insert(this);
00168 
00169   // -- Memoize this computation so that it's not so expensive
00170 
00171   if (_times_called != -1)
00172     return _times_called;
00173 
00174   // -- Main is called exactly once
00175 
00176   if (_called_by.empty())
00177     total = 1;
00178   else {
00179 
00180     // -- The number of times a procedure is called is the sum of the times
00181     // it is called by it's predecessors in the graph. We just have to be
00182     // careful to avoid recursion.
00183 
00184     for (callgraph_edge_list_p p = _called_by.begin();
00185          p != _called_by.end();
00186          ++p)
00187       {
00188         callGraphNode * caller = *p;
00189         total += caller->times_called(visited);
00190       }
00191   }
00192   
00193   _times_called = total;
00194 
00195   return total;
00196 }
00197 
00198 void callGraphNode::ancestors(callgraph_node_set & ancestors_set)
00199 {
00200   // -- Visit all the immediate callers
00201 
00202   for (callgraph_edge_list_p p = _called_by.begin();
00203        p != _called_by.end();
00204        ++p)
00205     {
00206       callGraphNode * caller = *p;
00207 
00208       // -- If the caller is not in the set, add it and go recursively up.
00209 
00210       if (ancestors_set.find(caller) == ancestors_set.end()) {
00211         ancestors_set.insert(caller);
00212         caller->ancestors(ancestors_set);
00213       }
00214     }
00215 }
00216 

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