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  

path.cc

Go to the documentation of this file.
00001 // $Id: path.cc,v 1.4 2003/08/07 23:14:27 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 #include "c_breeze.h"
00039 #include "path.h"
00040 
00041 // ------------------------------------------------------------
00042 // Path
00043 // ------------------------------------------------------------
00044 
00045 const Path * Path::Always = new Path();
00046 
00047 Path::Path(PathDB * db, const Path * parent,
00048                  procNode * proc)
00049   : Location(proc, 0, 0),
00050     _parent(0),
00051     _depth(0),
00052     // _refs(0),
00053     _dominates_exit(false),
00054     _db(0)
00055 {
00056   if (parent) {
00057     _parent = db->intern(parent);
00058     _depth = 1 + _parent->depth();
00059     // _parent->inc_refs();
00060   }
00061 }
00062 
00063 Path::Path(PathDB * db, const Path * parent,
00064                  procNode * proc, basicblockNode * block)
00065   : Location(proc, block, 0),
00066     _parent(0),
00067     _depth(0),
00068     // _refs(0),
00069     _dominates_exit(false),
00070     _db(0)
00071 {
00072   if (parent) {
00073     _parent = db->intern(parent);
00074     _depth = 1 + _parent->depth();
00075     // _parent->inc_refs();
00076   }
00077 }
00078 
00079 Path::Path(PathDB * db, const Path * parent,
00080                  const Location & loc)
00081   : Location(loc),
00082     _parent(0),
00083     _depth(0),
00084     // _refs(0),
00085     _dominates_exit(false),
00086     _db(0)
00087 {
00088   if (parent) {
00089     _parent = db->intern(parent);
00090     _depth = 1 + _parent->depth();
00091     // _parent->inc_refs();
00092   }
00093 }
00094 
00095 // --- Copy constructor: copy the given object, but make it unrecorded
00096 
00097 Path::Path(const Path & other)
00098   : Location(other),
00099     _parent(other._parent),
00100     _depth(other._depth),
00101     // _refs(0),
00102     _dominates_exit(false),
00103     _db(0)
00104 {
00105   // if (_parent)
00106   //  _parent->inc_refs();
00107 }
00108 
00109 // --- Private default constructor for creating internal static paths
00110 
00111 Path::Path()
00112   : Location(0, 0, 0),
00113     _parent(0),
00114     _depth(0),
00115     // _refs(0),
00116     _dominates_exit(false),
00117     _db(0)
00118 {}
00119 
00120 // --- Destructor
00121 
00122 Path::~Path()
00123 {
00124   if (_db)
00125     cerr << "ERROR: Attempted to delete a recorded path:" << *this << endl;
00126 
00127   // if (_refs)
00128   //  cerr << "ERROR: Attempted to delete a referenced path:" << *this << endl;
00129 
00130   // if (_parent)
00131   //   _parent->dec_refs();
00132 }
00133 
00134 // --- Check for recursion in the path sequence
00135 
00136 bool Path::is_recursive() const
00137 {
00138   if (is_always())
00139     return false;
00140 
00141   procNode * cur = proc();
00142   const Path * par = parent();
00143 
00144   while (par) {
00145     if (par->proc() == cur)
00146       return true;
00147     par = par->parent();
00148   }
00149 
00150   return false;
00151 }
00152 
00153 bool Path::is_proc_present(procNode * cur_proc) const
00154 {
00155   if (is_always())
00156     return false;
00157 
00158   const Path * par = this;
00159 
00160   while (par) {
00161     if (par->proc() == cur_proc)
00162       return true;
00163     par = par->parent();
00164   }
00165 
00166   return false;
00167 }
00168 
00169 
00170 // ------------------------------------------------------------
00171 // PathDB
00172 // ------------------------------------------------------------
00173 
00174 PathDB::PathDB()
00175   : _paths()
00176 {}
00177 
00178 // Equal_path is a comparator class for use in the find_if
00179 // algorithm.
00180 
00181 class Equal_path
00182 {
00183 public:
00184   const Path * _path_to_look_for;
00185 
00186   Equal_path(const Path * path_to_look_for)
00187     : _path_to_look_for(path_to_look_for)
00188   {}
00189 
00190   bool operator()(const pair<const Path * const, const Path *> & entry) {
00191     const Path * cur = entry.second;
00192     if (cur == _path_to_look_for)
00193       return true;
00194 
00195     return Location::equals(*cur, *_path_to_look_for);
00196   }
00197 };  
00198 
00199 // --- Look up a path, without creating a new entry. If the path
00200 // doesn't exist in the database, then it returns null.
00201 
00202 const Path * PathDB::lookup(const Path * con)
00203 {
00204   if (con) {
00205 
00206     if (con->is_always())
00207       return con;
00208 
00209     // --- Invariant: the parent must already be interned
00210 
00211     const Path * parent = con->parent();
00212 
00213     // --- First, look up all paths under the given parent
00214 
00215     pair<path_map_cp, path_map_cp> range = _paths.equal_range(parent);
00216 
00217     // --- Search for the proper location
00218 
00219     path_map_cp p = find_if(range.first, range.second, Equal_path(con));
00220 
00221     if ((p != _paths.end()) &&
00222         (p != range.second))
00223       return (*p).second;
00224   }
00225 
00226   return 0;
00227 }
00228 
00229 // Record a path in the database, eliminating duplicates and
00230 // sharing internal structure.
00231 
00232 const Path * PathDB::intern(const Path * con)
00233 {
00234   if (con) {
00235 
00236     const Path * orig = lookup(con);
00237 
00238     if (orig)
00239       return orig;
00240     else {
00241 
00242       // --- Create a new entry
00243 
00244       bool dom_exit;
00245       if ( ! con->is_always())
00246         dom_exit = Location::strictly_dominates(*con,
00247                                                 Location::exit(*con));
00248       else
00249         dom_exit = true;
00250 
00251       Path * new_intern = new Path(*con);
00252       new_intern->_dominates_exit = dom_exit;
00253       new_intern->_db = this;
00254 
00255       // --- Insert it into the map, indexed by it's parent
00256 
00257       path_map_pair entry(con->parent(), new_intern);
00258       _paths.insert(entry);
00259 
00260       return new_intern;
00261     }
00262   }
00263   else
00264     cout << "ERROR: Interning a null path" << endl;
00265   
00266   return 0;
00267 }  
00268 
00269 bool PathDB::equals(const Path * one, const Path * two)
00270 {
00271   if (one == two)
00272     return true;
00273 
00274   if ( ! (one && two))
00275     return false;
00276 
00277   if (Location::equals(*one, *two))
00278     return (one->parent() == two->parent());
00279 
00280   return false;
00281 }
00282 
00283 // --- Path dominance: this method extends the concept of dominance
00284 // to the full call-graph. However, it is specifically tailored for
00285 // tracking assignments when dealing with path prefixes (see cases 2
00286 // and 3 below).
00287 
00288 // Given two paths DOM and CUR, the function works as follows:
00289 
00290 // 1. If DOM and CUR are identical, return false
00291 
00292 // 2. If DOM is a prefix of CUR, return false. This logic for this is
00293 // that we want assignments inside a function call to precede (and be
00294 // visible to) the assignment of its return value.
00295 
00296 // 3. If CUR is a prefix of DOM, return true (see logic above).
00297 
00298 // 4. If DOM and CUR have the same parent path, compare dominance
00299 // at the local level. Otherwise, move up until we find a common
00300 // parent in which to perform local dominance comparison. In addition,
00301 // we need to make sure that DOM dominates the exit nodes of each
00302 // path that we move up through. This can be visualized in this
00303 // example:
00304 
00305 // DOM = {main:6, foo:3, bar:8, zag:2 }
00306 // CUR = {main:6, foo:3, bar:5, cats:6, dogs:2, fish:7}
00307 
00308 // DOM and CUR are identical up to foo:3. So, if bar:8 dominates
00309 // bar:5, AND zag:2 dominates the exit of function zag, the DOM
00310 // dominates CUR. We don't need to worry about the chain down from
00311 // bar:5 because clearly any path through fish:7 must pass through
00312 // bar:5.
00313 
00314 
00315 bool PathDB::dominates(const Path * dom, const Path * cur)
00316 {
00317   if (equals(dom, cur))
00318     return true;
00319 
00320   return strictly_dominates(dom, cur);
00321 }
00322 
00323 bool PathDB::strictly_dominates(const Path * dom, const Path * cur)
00324 {
00325   //  cout << "   Compare " << *dom << " >?> " << *cur << endl;
00326 
00327   // CASE 1: Equal paths, no strict dominance
00328 
00329   if (equals(dom, cur))
00330     return false;
00331 
00332   // CASE 1.5: "Always" dominates everything
00333 
00334   if (dom->is_always())
00335     return true;
00336 
00337   int depth_dom = dom->depth();
00338   int depth_cur = cur->depth();
00339   int min_depth = (depth_dom < depth_cur) ? depth_dom : depth_cur;
00340   int tmp;
00341 
00342   const Path * dom_p = dom;
00343   const Path * cur_p = cur;
00344 
00345   // --- Move up the dom call chain, collecting the dominates-exit values.
00346 
00347   bool dom_exit = true;
00348 
00349   while (dom_p && (dom_p->depth() > min_depth)) {
00350     dom_exit = dom_exit && dom_p->dominates_exit();
00351     dom_p = dom_p->parent();
00352   }
00353 
00354   // --- Move up the cur call chain
00355 
00356   while (cur_p && (cur_p->depth() > min_depth))
00357     cur_p = cur_p->parent();
00358 
00359   // CASE 2: Dominator is a prefix of the current: return false
00360   // CASE 3: Curhistoryrent is a prefix of the dominator: return true
00361 
00362   //  cout << "      Sub-Compare " << *dom_p << " >?> " << *cur_p << endl;
00363 
00364   if (equals(dom_p, cur_p))
00365     return (depth_dom > depth_cur);
00366 
00367   // --- Find a common parent
00368 
00369   while (dom_p && cur_p &&
00370          (! equals(dom_p->parent(), cur_p->parent()))) {
00371     dom_exit = dom_exit && dom_p->dominates_exit();
00372     dom_p = dom_p->parent();
00373     cur_p = cur_p->parent();
00374   }   
00375 
00376   // --- CASE 4: Found a common parent, so test dominance locally
00377 
00378   if (dom_p && cur_p) {
00379     bool res = (Location::strictly_dominates( *dom_p, *cur_p ) && dom_exit);
00380     return res;
00381   }
00382 
00383   // --- CASE 5: This shouldn't happen
00384 
00385   cerr << "ERROR: Cannot determine path dominance." << endl;
00386   return false;
00387 }
00388 
00389 // --- Print some statistics
00390 
00391 void PathDB::stats()
00392 {
00393   cout << "CLASS: PathDB" << endl;
00394   cout << "  Total number of path nodes: " << _paths.size() << endl;
00395   cout << "  Total memory used (bytes): " <<
00396     _paths.size() * (sizeof(path_map::value_type) + sizeof(Path)) << endl;
00397 }
00398 
00399 void PathDB::print(ostream & o) const
00400 {
00401   for (path_map_cp p = _paths.begin();
00402        p != _paths.end();
00403        ++p)
00404     {
00405       const Path * cur = (*p).second;
00406       cur->print_shallow(o);
00407       o << " in ";
00408       cur->parent()->print_shallow(o);
00409       o << endl;
00410     }
00411 }
00412 

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