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  

proceduredb.cc

Go to the documentation of this file.
00001 // $Id: proceduredb.cc,v 1.45 2003/08/08 15:16:29 toktb 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 <iomanip>
00040 #include <algorithm>
00041 #include "proceduredb.h"
00042 #include "memoryblock.h"
00043 
00044 procedureDB::procedureDB()
00045   : Walker(Preorder, Subtree),
00046     _procedures(),
00047     _callgraph(0),
00048     _need_reanalysis(),
00049     _root(0),
00050     _callstack(),
00051     _worklist()
00052 {}
00053 
00054 procedureDB::~procedureDB()
00055 {
00056   clear();
00057 }
00058 
00059 void procedureDB::build(procNode * root, Linker & linker)
00060 {
00061   // Make sure the DB is empty
00062   // Don't do this: clear();
00063 
00064   if (pointerOptions::Verbose)
00065     cout << "procedureDB::build " << root->decl()->name() << endl;
00066     
00067   // -- Build the call graph
00068 
00069   _callgraph = new callGraph(root, linker);
00070 
00071   // -- Create entries for each procedure definition
00072 
00073   const proc_decl_map & procs = linker.procedures();
00074   for (proc_decl_map_cp p = procs.begin();
00075        p != procs.end();
00076        ++p)
00077     add_procedure((*p).second);
00078 
00079   // -- Populate the ancestors set for each procedure
00080 
00081   for (proc_info_map_p p = _procedures.begin();
00082        p != _procedures.end();
00083        ++p)
00084     {
00085       procNode * proc = (*p).first;
00086       procedureInfo * info = (*p).second;
00087 
00088       // -- Look up the callgraph node
00089 
00090       callGraphNode * node = _callgraph->lookup(proc);
00091 
00092       // -- Build the ancestor set
00093 
00094       callgraph_node_set cg_ancestors;
00095       node->ancestors(cg_ancestors);
00096 
00097       // -- Translate that set into a procedureInfo set
00098 
00099       procedureinfo_set ancestors;
00100 
00101       for (callgraph_node_set_p q = cg_ancestors.begin();
00102            q != cg_ancestors.end();
00103            ++q)
00104         {
00105           callGraphNode * cg_ancestor = *q;
00106 
00107           // -- Look up the ancestor and add it to the set
00108 
00109           procedureInfo * ancestor = lookup(cg_ancestor->proc());
00110           ancestors.insert(ancestor);
00111         }
00112 
00113       // -- Pass the ancestor set to the procedure
00114 
00115       info->add_ancestor_set(ancestors);
00116 
00117       // -- Mark recursive procedures
00118 
00119       if (ancestors.find(info) != ancestors.end()) {
00120         info->set_recursive();
00121         cout << " + " << info->qualified_name() << " is recursive" << endl;
00122       }
00123     }
00124 
00125   // -- Store the root
00126 
00127   _root = lookup(root);
00128 }
00129 
00130 void procedureDB::clear()
00131 {
00132   for (proc_info_map_p p = _procedures.begin();
00133        p != _procedures.end();
00134        ++p) {
00135     delete (*p).second;
00136   }
00137 
00138   _procedures.clear();
00139 
00140   delete _callgraph;
00141   _callgraph = 0;
00142 }
00143 
00144 // Add a procedure to the database. This method is called during the
00145 // construction of the procedure database, but can also be called for other
00146 // procedures that are not immediately accessible, but will be needed later
00147 // (e.g., in the Broadway compiler).
00148 
00149 void procedureDB::add_procedure(procNode * proc)
00150 {
00151   string & name = proc->decl()->name();
00152 
00153   if (pointerOptions::Verbose)
00154     cout << "procedureDB: Add procedure " << name << endl;
00155 
00156   _procedures[proc] = new procedureInfo(proc);
00157 }
00158 
00159 procedureInfo * procedureDB::lookup(procNode * proc)
00160 {
00161   proc_info_map_p p = _procedures.find(proc);
00162   if (p != _procedures.end())
00163     return (*p).second;
00164   else
00165     return 0;
00166 }
00167 
00173 bool procedureDB::is_recursive_call(procedureInfo * callee,
00174                                     int & num_instances)
00175 {
00176   // -- There are a couple of possible implementations of this routine. One
00177   // is to just see if the current top of the stack is an ancestor to the
00178   // callee. This will cause us to skip all recursive cycles. The other is
00179   // to just check to see if the given procedure is already in the call
00180   // stack. This could be much more expensive, but more accurate.
00181 
00182   bool result = false;
00183   num_instances = 0;
00184 
00185   // -- This is option 2:
00186 
00187   for (procedurecall_stack_p p = _callstack.begin();
00188        p != _callstack.end();
00189        ++p)
00190     {
00191       procedureInfo * current = (*p).second;
00192       if (current == callee) {
00193         result = true;
00194         num_instances++;
00195       }
00196     }
00197 
00198   if (result && ( ! callee->is_recursive())) {
00199     /*
00200     cout << "RECURSION ERROR: procedure " << callee->qualified_name()
00201          << " -- callstack : ";
00202     print_call_stack(cout);
00203     cout << endl;
00204     */
00205 
00206     callee->set_recursive();
00207   }
00208 
00209   return result;
00210 }
00211 
00218 void procedureDB::call_to(stmtLocation * callsite, procedureInfo * callee)
00219 {
00220   // -- Push the newly called procedure on the callstack along with the
00221   // callsite.
00222 
00223   procedurecall_pair cp(callsite, callee);
00224   _callstack.push_back(cp);
00225 }
00226 
00232 void procedureDB::return_from()
00233 {
00234   // -- Just pop the stack
00235 
00236   _callstack.pop_back();
00237 }
00238 
00243 void procedureDB::setup_analysis()
00244 {
00245   for (proc_info_map_p p = _procedures.begin();
00246        p != _procedures.end();
00247        ++p)
00248     {
00249       procedureInfo * info = (*p).second;
00250       if (info != _root)
00251         _need_reanalysis.insert(info);
00252     }
00253 }
00254 
00255 bool procedureDB::is_visible_to_caller(procedureInfo * info,
00256                                        memoryBlock * block)
00257 {
00258   // -- Short circuit: if the variable is not local to any procedure, then
00259   // it's always in accessible.
00260 
00261   procNode * proc = block->local_to();
00262 
00263   if ( ! proc)
00264     return true;
00265 
00266   if ( ! info)
00267     return false;
00268 
00269   // -- Another quick out: if the variable is local to the given procedure,
00270   // then it can't be visible to the caller.
00271 
00272   if (proc == info->proc())
00273     return false;
00274 
00275   // -- Look up the owning procedure
00276 
00277   procedureInfo * owner = lookup(proc);
00278 
00279   /* -- This doesn't work when we use the call chain (rather than the
00280   ancestor set) to control recursion
00281 
00282  // -- See if it's in the ancestor set
00283 
00284   const procedureinfo_set & ancestors = info->ancestors();
00285 
00286   procedureinfo_set_cp found = ancestors.find(owner);
00287 
00288   if (found != ancestors.end())
00289     return true;
00290   else
00291     return false;
00292 
00293   */
00294 
00295   // -- Inspect the call stack to see if the variable is owned by any other
00296   // procedures. Start at the bottom of the stack (earlier).
00297 
00298   procedurecall_stack_p p = _callstack.begin();
00299   while (p != _callstack.end()) {
00300 
00301     procedureInfo * cur = (*p).second;
00302 
00303     // -- If we find the given procedure, then the search failed
00304 
00305     if (cur == info)
00306       return false;
00307 
00308     // -- If we find the owner of the variable, return true
00309 
00310     if (cur == owner)
00311       return true;
00312 
00313     ++p;
00314   }
00315 
00316   /* Obsolete:
00317   // -- Look up the call chain to see if the variable is in scope
00318 
00319   procedureInfo * caller = info->current_caller();
00320   while (caller) {
00321     caller = caller->current_caller();
00322     if (caller == owner)
00323       return true;
00324   }
00325   */
00326 
00327   return false;
00328 }
00329 
00336 bool procedureDB::is_visible_to(procedureInfo * info,
00337                                 memoryBlock * block)
00338 {
00339   // -- Short circuit: if the variable is not local to any procedure, then
00340   // it's always in accessible.
00341 
00342   procNode * proc = block->local_to();
00343 
00344   if ( ! proc)
00345     return true;
00346 
00347   if ( ! info)
00348     return false;
00349 
00350   // -- Another quick out: if the variable is local to the given procedure:
00351 
00352   if (proc == info->proc())
00353     return true;
00354 
00355   // -- Look up the owning procedure
00356 
00357   procedureInfo * owner = lookup(proc);
00358 
00359  // -- See if it's in the ancestor set
00360 
00361   const procedureinfo_set & ancestors = info->ancestors();
00362 
00363   procedureinfo_set_cp found = ancestors.find(owner);
00364 
00365   if (found != ancestors.end())
00366     return true;
00367   else
00368     return false;
00369 }
00370 
00375 procedureInfo * procedureDB::current_caller()
00376 {
00377   // -- Get the end of the call stack
00378 
00379   procedurecall_stack::reverse_iterator p = _callstack.rbegin();
00380 
00381   // -- Go to the second to last element
00382 
00383   p++;
00384 
00385   // -- If its not the rend, then return it
00386 
00387   if ( ! (p == _callstack.rend()) )
00388     return (*p).second;
00389   else
00390     return 0;
00391 }
00392 
00397 void procedureDB::clear_call_stack()
00398 {
00399   _callstack.clear();
00400 
00401   // -- Initialize the call stack with the root procedure
00402 
00403   procedurecall_pair root_entry((stmtLocation *)0, _root);
00404   _callstack.push_back(root_entry);
00405 }
00406 
00407 
00408 void procedureDB::print_call_stack(ostream & out)
00409 {
00410   bool first = true;
00411 
00412   if (_callstack.empty())
00413     out << "(empty)";
00414   else {
00415 
00416     for (procedurecall_stack_p p = _callstack.begin();
00417          p != _callstack.end();
00418          ++p)
00419       {
00420         stmtLocation * s = (*p).first;
00421 
00422         if (s) {
00423           s->print_callsite(cout);
00424           cout << '/';
00425         }
00426       }
00427 
00428     procedureInfo * top = _callstack.back().second;
00429     cout << top->name();
00430   }
00431 }
00432 
00433 void procedureDB::progress_meter(ostream & out)
00434 {
00435   for (procedurecall_stack_p p = _callstack.begin();
00436        p != _callstack.end();
00437        ++p)
00438     {
00439       procedureInfo * current = (*p).second;
00440 
00441       out << current->qualified_name();
00442     }
00443 }
00444 
00451 void procedureDB::mark_for_reanalysis(procedureInfo * info,
00452                                       stmtLocation * callsite,
00453                                       bool include_self)
00454 {
00455 
00456   pair< procedureinfo_set_p, bool> res;
00457   
00458   if (pointerOptions::Verbose) {
00459     cout << "  Mark for reanalysis: " << info->name();
00460 
00461     if (callsite)
00462       cout << " at " << *callsite << endl;
00463     else
00464       cout << " (no callsite)" << endl;
00465   }
00466 
00467   // -- Add the procedure itself, if need be.
00468 
00469   if (include_self)
00470     _need_reanalysis.insert(info);
00471 
00472   // -- New version: just provide a path to the right caller
00473 
00474   procedureInfo * current = info;
00475   while (current->first_caller()) {
00476 
00477     procedureInfo * first_caller = current->first_caller();
00478 
00479     res = _need_reanalysis.insert(first_caller);
00480     if (pointerOptions::Verbose) {
00481       if (res.second)
00482         cout << "      + " << first_caller->name() << endl;
00483       else
00484         cout << "      - " << first_caller->name() << endl;
00485     }
00486 
00487     current = first_caller;
00488   }
00489 
00490   /*
00491   // -- Add all of the procedures ancestors
00492 
00493   for (procedureinfo_set_cp q = info->ancestors().begin();
00494        q != info->ancestors().end();
00495        ++q)
00496     {
00497       res = _need_reanalysis.insert(*q);
00498       if (pointerOptions::Verbose) {
00499         if (res.second)
00500           cout << "      + " << (*q)->name() << endl;
00501         else
00502           cout << "      - " << (*q)->name() << endl;
00503       }
00504     }
00505   */
00506 }
00507 
00512 void procedureDB::mark_one_for_reanalysis(procedureInfo * info)
00513 {
00514   // -- Add the procedure itself to the list
00515 
00516   pair< procedureinfo_set_p, bool> res = _need_reanalysis.insert(info);
00517 } 
00518 
00525 bool procedureDB::is_reanalysis_required(procedureInfo * info)
00526 {
00527   if (pointerOptions::Verbose)
00528     cout << "Is analysis for " << info->name() << " mandatory?" << endl;
00529 
00530   // -- Look for this callgraph edge
00531 
00532   procedureinfo_set_p p = _need_reanalysis.find(info);
00533 
00534   // -- Return true if it's found
00535 
00536   if (p != _need_reanalysis.end()) {
00537     _need_reanalysis.erase(p);
00538 
00539     // -- Extra test: if it's in the callstack more than once, then don't
00540     // force reanalysis. This will allow recursion to converge faster.
00541     /*
00542     int instances = 0;
00543     procedurecall_stack_p q = _callstack.begin();
00544     while (q != _callstack.end()) {
00545 
00546       procedureInfo * cur = (*q).second;
00547 
00548       if (cur == info) {
00549         instances++;
00550 
00551         if (instances > 1) {
00552           if (pointerOptions::Verbose)
00553             cout << " ....no (in recursion)" << endl;
00554 
00555           return false;
00556         }
00557       }
00558 
00559       ++q;
00560     }
00561     */
00562     if (pointerOptions::Verbose)
00563       cout << " ....yes" << endl;
00564 
00565     return true;
00566   }
00567   else {
00568 
00569     if (pointerOptions::Verbose)
00570       cout << " ....no" << endl;
00571 
00572     return false;
00573   }
00574 }
00575 
00578 void procedureDB::print_leftovers()
00579 {
00580   cout << "Procedures that still need analysis:" << endl;
00581   for (procedureinfo_set_p p = _need_reanalysis.begin();
00582        p != _need_reanalysis.end();
00583        ++p)
00584     {      
00585       if ((*p)->analysis_count() > 0)
00586         cout << "  +" << (*p)->name() << endl;
00587     }
00588 }
00589 
00590 int procedureDB::times_called(procedureInfo * info)
00591 {
00592   callGraphNode * node = _callgraph->lookup(info->proc());
00593   return node->times_called();
00594 }
00595 
00596 void  procedureDB::stats(ostream & out)
00597 {
00598 
00599   if (pointerOptions::Show_procedures) {
00600 
00601     out.width(20);
00602     out << "Procedure";
00603 
00604     out.width(6);
00605     out << "CI";
00606 
00607     out.width(6);
00608     out << "Rec";
00609 
00610     out.width(8);
00611     out << "Sites";
00612 
00613     out.width(8);
00614     out << "X in";
00615 
00616     out.width(8);
00617     out << "X out";
00618 
00619     out.width(8);
00620     out << "Anc";
00621 
00622     out.width(8);
00623     out << "Calls";
00624 
00625     out.width(12);
00626     out << "Time (self)";
00627 
00628     out.width(12);
00629     out << "Time (total)";
00630 
00631     out.width(8);
00632     out << "Cont";
00633 
00634     out.width(8);
00635     out << "Size";
00636 
00637     out << endl;
00638 
00639     for (proc_info_map_p p = _procedures.begin();
00640          p != _procedures.end();
00641          ++p)
00642       {
00643         procedureInfo * info = (*p).second;
00644 
00645         if ( ! info->is_library_routine())
00646           info->stats(out);
00647       }
00648 
00649     out.width(0);
00650   }
00651 }
00652 
00655 void procedureDB::number_of_procedures(int & total, int & analyzed,
00656                                        int & context_insensitive,
00657                                        int & recursive,
00658                                        int & unanalyzed,
00659                                        int & program_size)
00660 {
00661   total = 0;
00662   analyzed = 0;
00663   context_insensitive = 0;
00664   recursive = 0;
00665   program_size = 0;
00666   unanalyzed = 0;
00667 
00668   for (proc_info_map_p p = _procedures.begin();
00669        p != _procedures.end();
00670        ++p)
00671     {
00672       procedureInfo * info = (*p).second;
00673 
00674       total++;
00675 
00676       if (info->analysis_count() > 0) {
00677         analyzed++;
00678 
00679         if (info->is_context_insensitive()) {
00680 
00681           context_insensitive++;
00682 
00683           if (info->is_recursive())
00684 
00685             recursive++;
00686         }
00687 
00688         program_size += info->procedure_size();
00689       }
00690       else
00691         if ( ! info->is_library_routine())
00692           unanalyzed++;
00693     }
00694 }
00695 
00696 
00697 // ------------------------------------------------------------
00698 // procedureInfo
00699 // ------------------------------------------------------------
00700 
00701 procedureInfo::procedureInfo(procNode * the_proc)
00702   : _proc(the_proc),
00703     _worklist(),
00704     _forward_worklist_order(),
00705     _forward_basicblock_order(),
00706     _backward_worklist_order(),
00707     _backward_basicblock_order(),
00708     _merge_points(),
00709     _dominance_frontiers(new DFPreds(the_proc)),
00710     _loops(new loopTree(the_proc)),
00711     _callsites(),
00712     _return_variable(0),
00713     _return_stmt(0),
00714     _never_returns(false),
00715     _context_insensitive(false),
00716     _prefer_context_sensitive(false),
00717     _only_context(0),
00718     _external_inputs(),
00719     _external_outputs(),
00720     _ancestors(),
00721     _first_caller(0),
00722     _calls(),
00723     _is_recursive(false),
00724     _blocks_to_skip(),
00725     _active_edges(),
00726     _true_branches(),
00727     _analysis_count(0),
00728     _verbose(false)
00729 {
00730 
00731   // -- Compute the forward ordering of the basic blocks (reverse
00732   // post-order)
00733 
00734   basicblock_set visited;
00735   basicblock_list order;
00736 
00737   // -- First compute the reverse post-order, so we can order the children
00738   // correctly.
00739 
00740   basicblock_list rpo_order;
00741 
00742   visited.clear();
00743   reverse_post_order(Forward, _proc->entry(), visited, rpo_order);
00744 
00745   // -- Now perform the depth-first traversal of the dominator tree
00746 
00747   visited.clear();
00748   dfs_dominators(Forward, _proc->entry(), visited, order, rpo_order);
00749 
00750   int size = order.size();
00751 
00752   // -- Store that ordering with two mappings: a mapping from basic blocks
00753   // to their indices, and from indices back to basic blocks (this is just
00754   // a vector).
00755 
00756   _forward_basicblock_order.resize(size);
00757   int cur = 0;
00758   for (basicblock_list_p p = order.begin();
00759        p != order.end();
00760        ++p)
00761     {
00762       basicblockNode * block = *p;
00763       _forward_basicblock_order[cur] = block;
00764       _forward_worklist_order[block] = cur;
00765       cur++;
00766     }
00767 
00768   // -- Now do the same for the reverse control-flow graph
00769 
00770   visited.clear();
00771   order.clear();
00772   reverse_post_order(Backward, _proc->exit(), visited, order);
00773 
00774   _backward_basicblock_order.resize(size);
00775   cur = 0;
00776   for (basicblock_list_p p = order.begin();
00777        p != order.end();
00778        ++p)
00779     {
00780       basicblockNode * block = *p;
00781       _backward_basicblock_order[cur] = block;
00782       _backward_worklist_order[block] = cur;
00783       cur++;
00784     }  
00785 
00786   // Set the max size of the worklist
00787 
00788   _worklist.max_size(size);
00789 
00790   // -- Find the return value variable. It must be the argumen to the
00791   // return statement of the exit basic block.
00792 
00793   basicblockNode * bb = _proc->exit();
00794   stmtNode * statement = bb->stmts().back();
00795 
00796   if (statement->typ() == Return) {
00797     returnNode * ret = (returnNode *) statement;
00798     _return_stmt = ret;
00799     if (ret->expr() &&
00800         ret->expr()->typ() == Id)
00801       {
00802         idNode * id = (idNode *) ret->expr();
00803         _return_variable = id->decl();
00804       }
00805   }
00806 
00807   // -- Build the true branch mapping
00808 
00809   typedef map< stmtNode *, basicblockNode * > label_location_map;
00810   typedef label_location_map::iterator label_location_map_p;
00811 
00812   label_location_map labels;
00813 
00814   for (basicblock_list_p p = order.begin();
00815        p != order.end();
00816        ++p)
00817     {
00818       basicblockNode * block = *p;
00819 
00820       // -- Find any labels
00821 
00822       for (stmt_list_p q = block->stmts().begin();
00823            q != block->stmts().end();
00824            ++q)
00825         {
00826           stmtNode * stmt = *q;
00827 
00828           // -- Record where the labels are
00829 
00830           if (stmt->typ() == Label) {
00831             labels[stmt] = block;
00832             labelNode * l = (labelNode *)stmt;
00833           }
00834         }
00835     }
00836 
00837   for (basicblock_list_p p = order.begin();
00838        p != order.end();
00839        ++p)
00840     {
00841       basicblockNode * block = *p;
00842 
00843       // -- Find the if statement
00844 
00845       for (stmt_list_p q = block->stmts().begin();
00846            q != block->stmts().end();
00847            ++q)
00848         {
00849           stmtNode * stmt = *q;
00850 
00851           if (stmt->typ() == Condition) {
00852             conditiongotoNode * cond = (conditiongotoNode *) stmt;
00853             labelNode * lab = cond->label();
00854             label_location_map_p ll = labels.find(lab);
00855             if (ll == labels.end())
00856               cout << "ERROR: No label " << lab->name() << " in " << name() << endl;
00857             else
00858               _true_branches[block] = (*ll).second;
00859           }
00860         }
00861     }
00862 
00863   // -- Check to see if this procedure is preferred context sensitive
00864 
00865   str_set_p cs = pointerOptions::Context_sensitive_procedures.find(_proc->decl()->name());
00866   if (cs !=  pointerOptions::Context_sensitive_procedures.end())
00867     _prefer_context_sensitive = true;
00868 
00869   // -- Check to see if the procedure should be verbose
00870 
00871   str_set_p vb = pointerOptions::Verbose_procedures.find(_proc->decl()->name());
00872   if (vb !=  pointerOptions::Verbose_procedures.end())
00873     _verbose = true;
00874 }
00875 
00876 procedureInfo::~procedureInfo()
00877 {
00878   delete _dominance_frontiers;
00879   delete _loops;
00880   delete _only_context;
00881 }
00882 
00883 void procedureInfo::add_ancestor_set(procedureinfo_set & ancestors)
00884 {
00885   _ancestors = ancestors;
00886 }
00887 
00888 void procedureInfo::setup_call_at(procedureInfo * caller, 
00889                                   stmtLocation * callsite,
00890                                   bool is_recursive_call,
00891                                   bool multiple_target_call)
00892 {
00893   // -- Decide if we want to make this call context-insensitive.
00894   // Three cases:
00895 
00896   //    1. The call is recursive: we must make the procedure
00897   //    context-sensitive (and there should be exactly one existing
00898   //    callsite).
00899 
00900   //    2. The callsite has multiple targets: make the procedure
00901   //    context-insensitive. However, if there are multiple callsites
00902   //    already, then we're in trouble.
00903 
00904   //    3. The analyzer is being run in CI mode and the given procedure
00905   //    doesn't prefer to be context sensitive (i.e., been marked CS by the
00906   //    adaptive algorithm).
00907   //
00908   //    4. The callsite already has a context-sensitive call, and it's to a
00909   //    different procedure.
00910 
00911   bool make_context_insensitive = false;
00912 
00913   if ((callsite->calls() &&
00914        (callsite->calls()->proc() != proc())) ||
00915       is_recursive() && /*TB*/ !pointerOptions::Recursion_Context_sensitive ||
00916       multiple_target_call ||
00917       (pointerOptions::Context_insensitive &&
00918        // (first_callsite != callsite) &&
00919        ! prefer_context_sensitive()))
00920     make_context_insensitive = true;
00921 
00922   // -- When context-insensitive
00923 
00924   if (make_context_insensitive &&
00925       ! is_context_insensitive())
00926     {
00927       // -- Make the procedure context insensitive
00928 
00929       _context_insensitive = true;
00930 
00931       // -- Find out about existing calling contexts
00932 
00933       stmtLocation * first_callsite = 0;
00934       bool multiple_callsites = false;
00935 
00936       if (_callsites.size() > 1)
00937         multiple_callsites = true;
00938       else {
00939         if (_callsites.size() == 1) {
00940           
00941           // -- Get the one context seen so far
00942           
00943           first_callsite = (* _callsites.begin()).first;
00944         }
00945       }
00946 
00947       if (first_callsite)
00948         _only_context = first_callsite->remove_call();
00949       else
00950         _only_context = new procLocation(callsite, proc(), true);
00951 
00952       if (pointerOptions::Verbose) {
00953         cout << "--> Make " << qualified_name() << " context-insensitive at " << * callsite << endl;
00954         if (multiple_callsites)
00955           cout << "     ** Multiple callsites exist: this could be a problem" << endl;
00956       }
00957     }
00958 
00959   // -- For context-sensitive calls, setup the new context
00960 
00961   if ( ! is_context_insensitive()) {
00962 
00963     // -- Set up the call site
00964 
00965     callsite->setup_cs_call(proc());
00966   }
00967 
00968   // -- Store the callsite information
00969 
00970   _callsites[callsite] = caller;
00971 
00972   // -- Record this procedure as being called
00973 
00974   caller->_calls.insert(this);
00975 
00976   // -- See if this is the first caller
00977 
00978   if ( ! _first_caller)
00979     _first_caller = caller;
00980 }
00981 
00987 string procedureInfo::qualified_name()
00988 {
00989   string nm(name());
00990 
00991   if (is_context_insensitive()) {
00992     if (is_recursive())
00993       nm += "(R)";
00994     else
00995       nm += "(I)";
00996   }
00997   else
00998     nm += "(S)";
00999 
01000   if (never_returns())
01001     nm += "!";
01002 
01003   char temp[200];
01004 
01005   sprintf(temp, "[%d,%d,%d,%6.2f/%6.2f]",
01006           _callsites.size(),
01007           _external_inputs.size(),
01008           _external_outputs.size(),
01009           self_timer(), total_timer());
01010 
01011   nm += temp;
01012 
01013   return nm;
01014 }
01015 
01065 void procedureInfo::set_pending_changes(stmtLocation * callsite, memoryblock_set & changes)
01066 {
01067   // -- Add the given changes into the pending changes set
01068 
01069   _pending_changes[callsite].insert(changes.begin(), changes.end());
01070 }
01071 
01078 void procedureInfo::get_pending_changes(stmtLocation * callsite, memoryblock_set & changes)
01079 {
01080   // -- Find the given callsite
01081 
01082   callsite_changes_map_p p = _pending_changes.find(callsite);
01083 
01084   if (p != _pending_changes.end()) {
01085 
01086     // -- Found some changes, merge them in
01087 
01088     memoryblock_set & new_changes = (*p).second;
01089 
01090     // -- Set the current def to the external output def
01091 
01092     for (memoryblock_set_p q = new_changes.begin();
01093          q != new_changes.end();
01094          ++q)
01095       {
01096         memoryBlock * pending_change = (*q);
01097 
01098         // -- Find the def at the callsite (there must be one, because
01099         // these blocks are external outputs).
01100 
01101         pending_change->set_current_def_use(callsite);
01102 
01103         // -- Add it to the changes set
01104 
01105         changes.insert(pending_change);
01106       }
01107 
01108     // -- Erase the entry
01109 
01110     _pending_changes.erase(p);
01111   }
01112 }
01113 
01118 procedureInfo * procedureInfo::caller_at(stmtLocation * callsite)
01119 {
01120   callsite_map_p p = _callsites.find(callsite);
01121   if (p != _callsites.end())
01122     return (*p).second;
01123 
01124   return 0;
01125 }
01126 
01131 bool procedureInfo::is_ancestor(procedureInfo * other)
01132 {
01133   procedureinfo_set_p p = _ancestors.find(other);
01134 
01135   return (p != other->_ancestors.end());
01136 }
01137 
01144 procLocation * procedureInfo::procedure_location(stmtLocation * callsite)
01145 {
01146   if (is_context_insensitive())
01147     return _only_context;
01148 
01149   return callsite->calls();
01150 }
01151 
01152 // ----------------------------------------------------------------------
01153 //  Manage external inputs and outputs
01154 // ----------------------------------------------------------------------
01155 
01156 bool procedureInfo::add_external_input(memoryBlock * block)
01157 {
01158   // -- Each use with an external reaching def is considered an input
01159 
01160   if (_external_inputs.find(block) == _external_inputs.end()) {
01161 
01162     _external_inputs.insert(block);
01163 
01164     if (pointerOptions::Verbose)
01165       cout << "   Added external input " << block->name() << endl;
01166 
01167     return true;
01168   }
01169   else
01170     return false;
01171 }
01172 
01173 bool procedureInfo::add_external_output(memoryBlock * block)
01174 {
01175   bool found_new_output = false;
01176 
01177   // -- Each externally visible def is considered an output
01178 
01179   if (_external_outputs.find(block) == _external_outputs.end()) {
01180 
01181     _external_outputs.insert(block);
01182 
01183     if (pointerOptions::Verbose) {
01184       cout << "   New external output " << block->name() << endl;
01185     }
01186 
01187     // -- Also, make sure weak updates are represented in the
01188     // external inputs list.
01189 
01190     if (block->current_def() &&
01191         (block->current_def()->is_weak()))
01192       {
01193         if (add_external_input(block)) {
01194           found_new_output = true;
01195           if (pointerOptions::Verbose)
01196             cout << "    (Caused by weak update)" << endl;
01197         }
01198       }
01199 
01200     return found_new_output;
01201   }
01202   else
01203     return false;
01204 }
01205 
01206 // ----------------------------------------------------------------------
01207 //  Merge point management
01208 // ----------------------------------------------------------------------
01209 
01210 void procedureInfo::setup_merge_point(memoryBlock * block_to_merge,
01211                                       basicblockLocation * cur)
01212 {
01213   // -- Flow insensitive objects have no merge points
01214 
01215   if ( ! block_to_merge->is_flow_sensitive())
01216     return;
01217 
01218   // -- Don't merge temporaries: crap, this doesn't work for the ternary
01219   // operator.
01220 
01221   /*
01222   const char * nm = block_to_merge->decl()->name().c_str();
01223   if ((strncmp(nm, "__TE", 4) == 0) ||
01224       (strncmp(nm, "__IE", 4) == 0))
01225     return;
01226   */
01227 
01228   procLocation * proc_loc = cur->proc_location();
01229 
01230   // --- First, find all the places where merge points should be
01231   // (dominance frontier).
01232 
01233   bool found_dominance_frontier = false;
01234 
01235   basicblock_set_map_map_p p = _dominance_frontiers->find(cur->block());
01236   if ((p != _dominance_frontiers->end()) &&
01237       ! (*p).second.empty()) {
01238 
01239     found_dominance_frontier = true;
01240 
01241     // --- Found a dominance frontier entry
01242 
01243     basicblock_set_map & df = (*p).second;
01244 
01245     // --- Visit each entry in the dominance frontier. This formulation
01246     // includes the set of predecessors.
01247     
01248     for (basicblock_set_map_p bbq = df.begin();
01249          bbq != df.end();
01250          ++bbq)
01251       {
01252         basicblockNode * merge_basicblock = (*bbq).first;
01253         basicblockLocation * merge_location = proc_loc->lookup_block(merge_basicblock);
01254         basicblock_set & predecessors = (*bbq).second;
01255 
01256         // -- Get the reaching def. If it occured inside a called
01257         // procedure, then the current_def field will be null and we'll
01258         // need to find the reaching def.
01259 
01260         memoryDef * cur_def = block_to_merge->current_def();
01261         memoryDef * def;
01262 
01263         if ( cur_def )
01264           def = cur_def;
01265         else
01266           def = block_to_merge->nearest_def_at(cur->last());
01267 
01268         if ( ! def ) {
01269 
01270           // -- Actually, this is okay in one specific case: we can have an
01271           // object that is modified, and later merged, but then hit a
01272           // never-returns situation:
01273           //
01274           // if (foo) {
01275           //     sprintf(buffer,...);
01276           //     printf(buffer);
01277           // }
01278           // exit(0)
01279           //
01280           // We will record the buffer as a change at the merge point
01281           // before realizing that the changes don't escape. In this case,
01282           // the caller may receive an external change with no reaching
01283           // def.
01284 
01285           /*
01286           cout << "MERGE-ERROR at: " << * cur << endl;
01287           cout << "  Could not find def that dominates " << * (cur->last()) << endl;
01288           block_to_merge->print_def_use(cout);
01289           cout << endl;
01290           */
01291         }
01292         else {
01293 
01294           // -- Set up the merge point: create the special phi uses.
01295             
01296           block_to_merge->setup_merge_uses_at(merge_location, def, predecessors);
01297           _merge_points[merge_location].insert(block_to_merge);
01298             
01299           if (pointerOptions::Verbose)
01300             cout << "      Merge " << block_to_merge->name() << " at "
01301                  << * merge_location << endl;
01302         }
01303       }
01304   }
01305 
01306   if (pointerOptions::Verbose && found_dominance_frontier)
01307     cout << endl;
01308 }
01309 
01310 // --- Find the set of objects to be merged at a particular basic
01311 // block entry point.
01312 
01313 memoryblock_set * procedureInfo::lookup_merge_point(basicblockLocation * merge_location)
01314 {
01315   if (pointerOptions::Verbose) {
01316     cout << " Lookup merge: " << *merge_location << endl;
01317   }
01318 
01319   mergepoint_map_p p = _merge_points.find(merge_location);
01320   if (p == _merge_points.end()) {
01321     if (pointerOptions::Verbose) {
01322       cout << "    None found." << endl;
01323       cout << endl;
01324     }
01325     return 0;
01326   }
01327   else {
01328     if (pointerOptions::Verbose) {
01329       memoryblock_set & objects = (*p).second;
01330       for (memoryblock_set_cp q = objects.begin();
01331            q != objects.end();
01332            ++q)
01333         cout << "    Merge: " << (*q)->name() << endl;
01334     }
01335 
01336     if (pointerOptions::Verbose)
01337       cout << endl;
01338 
01339     return &((*p).second);
01340   }
01341 }
01342 
01343 void procedureInfo::check_merge_point(memoryBlock * block_to_merge,
01344                                       basicblockLocation * cur)
01345 {
01346   // -- Flow insensitive objects have no merge points
01347 
01348   if ( ! block_to_merge->is_flow_sensitive())
01349     return;
01350 
01351   procLocation * proc_loc = cur->proc_location();
01352 
01353   // --- First, find all the places where merge points should be
01354   // (dominance frontier).
01355 
01356   bool found_dominance_frontier = false;
01357 
01358   basicblock_set_map_map_p p = _dominance_frontiers->find(cur->block());
01359   if ((p != _dominance_frontiers->end()) &&
01360       ! (*p).second.empty()) {
01361 
01362     found_dominance_frontier = true;
01363 
01364     // --- Found a dominance frontier entry
01365 
01366     basicblock_set_map & df = (*p).second;
01367 
01368     // --- Visit each entry in the dominance frontier. This formulation
01369     // includes the set of predecessors.
01370     
01371     for (basicblock_set_map_p bbq = df.begin();
01372          bbq != df.end();
01373          ++bbq)
01374       {
01375         basicblockNode * merge_basicblock = (*bbq).first;
01376         basicblockLocation * merge_location = proc_loc->lookup_block(merge_basicblock);
01377         basicblock_set & predecessors = (*bbq).second;
01378 
01379         // -- Get the reaching def. If it occured inside a called
01380         // procedure, then the current_def field will be null and we'll
01381         // need to find the reaching def.
01382 
01383         memoryDef * cur_def = block_to_merge->current_def();
01384         memoryDef * def;
01385 
01386         if ( cur_def )
01387           def = cur_def;
01388         else
01389           def = block_to_merge->last_def_at(cur);
01390 
01391         // -- This is the check: there had better be a def at the
01392         // merge-point by now.
01393 
01408       }
01409   }
01410 
01411   if (pointerOptions::Verbose && found_dominance_frontier)
01412     cout << endl;
01413 }
01414 
01415 // ----------------------------------------------------------------------
01416 //   Worklist management
01417 // ----------------------------------------------------------------------
01418 
01419 void procedureInfo::reverse_post_order(Direction dir,
01420                                        basicblockNode * cur,
01421                                        basicblock_set & visited,
01422                                        basicblock_list & order)
01423 {
01424   // If the node is not already there, then process it.
01425 
01426   if (visited.find(cur) == visited.end()) {
01427     visited.insert(cur);
01428 
01429     // For post-order, we process the children first. Note that we visit
01430     // the children in *reverse* order because we're building the list from
01431     // back to front.
01432 
01433     // -- Choose successors or predecessors depending on the direction
01434 
01435     basicblock_list & children = (dir == Forward) ? cur->succs() : cur->preds();
01436 
01437     // -- Improvement: use the loopTree object to make sure we visit back-edges first.
01438 
01439     for (basicblock_list::reverse_iterator p = children.rbegin();
01440          p != children.rend();
01441          ++p)
01442       {
01443         basicblockNode * child = *p;
01444         if (_loops->classifyEdge(cur, child) != loopTree::BackEdge)
01445           reverse_post_order(dir, child, visited, order);
01446       }
01447 
01448     for (basicblock_list::reverse_iterator p = children.rbegin();
01449          p != children.rend();
01450          ++p)
01451       {
01452         basicblockNode * child = *p;
01453         if (_loops->classifyEdge(cur, child) == loopTree::BackEdge)
01454           reverse_post_order(dir, child, visited, order);
01455       }
01456 
01457     // For reverse post-order, put the parent on the front of the
01458     // list.
01459 
01460     order.push_front(cur);
01461   }
01462 }
01463 
01464 void procedureInfo::dfs_dominators(Direction dir,
01465                                    basicblockNode * cur,
01466                                    basicblock_set & visited,
01467                                    basicblock_list & order,
01468                                    basicblock_list & rpo_order)
01469 {
01470   // If the node is not already there, then process it.
01471 
01472   if (visited.find(cur) == visited.end()) {
01473     visited.insert(cur);
01474     order.push_back(cur);
01475 
01476     // basicblockNode * last = 0;
01477 
01478     const basicblock_list & children = cur->children();
01479 
01480     // -- Make sure we order the children according to the
01481     // reverse-post-order.
01482 
01483     for (basicblock_list_p p = rpo_order.begin();
01484          p != rpo_order.end();
01485          ++p)
01486       {
01487         basicblockNode * child = *p;
01488 
01489         if (find(children.begin(), children.end(), child) != children.end())
01490           dfs_dominators(dir, child, visited, order, rpo_order);
01491       }
01492 
01493     /*
01494     for (basicblock_list_p p = cur->children().begin();
01495          p != cur->children().end();
01496          ++p)
01497       {
01498         basicblockNode * child = *p;
01499         
01500         if (Dominators::dominates(child, proc()->exit()))
01501           last = child;
01502         else
01503           dfs_dominators(dir, child, visited, order);
01504       }
01505 
01506     if (last)
01507       dfs_dominators(dir, last, visited, order, rpo_order);
01508     */
01509   }
01510 }
01511 
01512 basicblockNode * procedureInfo::get_next_block(Direction dir)
01513 {
01514   // When empty, return 0
01515 
01516   if (_worklist.is_empty())
01517     return 0;
01518 
01519   basicblockNode * next_block = block_at(_worklist.get_next_block(), dir);
01520 
01521   // cout << "WORKLIST: Get next block " << next_block->dfn() << endl;
01522 
01523   return next_block;
01524 }
01525 
01526 void procedureInfo::add_block(basicblockNode * block, Direction dir)
01527 {
01528   // Figure out where the bit should be
01529 
01530   int position = block_position(block, dir);
01531 
01532   // Add it to the worklist
01533 
01534   _worklist.add_block(position);
01535 
01536   // Remove it from the skip-list
01537 
01538   basicblock_set_p p = _blocks_to_skip.find(block);
01539   if (p != _blocks_to_skip.end())
01540     _blocks_to_skip.erase(p);
01541 
01542   // cout << "[ block=" <<  block->dfn() << ", position=" << position << " ] ";
01543 
01544   // cout << "WORKLIST: Add block " << block->dfn() << " at position " << position << endl;
01545 }
01546 
01547 void procedureInfo::add_reachable_blocks(basicblockNode * block, Direction dir)
01548 {
01549   // Make a temporary list for the depth-first search
01550 
01551   worklist_set temp;
01552 
01553   // Use the temporary list to perform a depth-first search, marking nodes
01554   // in the real worklist.
01555 
01556   // cout << "WORKLIST: add: ";
01557 
01558   add_reachable_blocks_rec(dir, block, temp, true);
01559 
01560   // _worklist.skip_current_block();
01561 
01562   // cout << endl;
01563 
01564   // cout << "WORKLIST: add_reachable_blocks, cur_size = " << _cur_size << endl;
01565 }
01566 
01567 void procedureInfo::add_reachable_blocks_rec(Direction dir,
01568                                              basicblockNode * cur,
01569                                              worklist_set & temp, bool first)
01570 {
01571   // Figure out where the bit should be
01572 
01573   int position = block_position(cur, dir);
01574 
01575   // Stop recursion when we find a bit set already
01576 
01577   if ( temp.test(position))
01578     return;
01579 
01580   // Skip the root basic block
01581 
01582   if (! first)
01583     add_block(cur, dir);
01584 
01585   // Update the temp to avoid visiting duplicates (also skip the root)
01586 
01587   if (! first)
01588     temp.set(position);
01589 
01590   // Add all successors or predecessors, depending on the direction argument
01591 
01592   basicblock_list & children = (dir == Forward) ? cur->succs() : cur->preds();
01593 
01594   for (basicblock_list_p p = children.begin();
01595        p != children.end();
01596        ++p)
01597     {
01598       basicblockNode * cur_child = *p;
01599       add_reachable_blocks_rec(dir, cur_child, temp, false);
01600     }
01601 }
01602 
01603 void procedureInfo::add_all_blocks()
01604 {
01605   _worklist.add_all_blocks();
01606 
01607   _blocks_to_skip.clear();
01608 
01609   _active_edges.clear();
01610 }      
01611 
01612 void procedureInfo::add_start_block(Direction dir)
01613 {
01614   // -- Depending on the direction, add either the entry node, or the exit
01615   // node.
01616 
01617   if (dir == Forward)
01618     add_block(proc()->entry(), dir);
01619   else
01620     add_block(proc()->exit(), dir);
01621 
01622   // cout << "WORKLIST: add_entry_block, cur_size = " << _cur_size << endl;
01623 }
01624 
01625 bool procedureInfo::is_empty() const
01626 {
01627   return _worklist.is_empty();
01628 }
01629 
01635 void procedureInfo::remove_branch_blocks(basicblockNode * cond,
01636                                          basicblockNode * branch_taken,
01637                                          basicblockNode * branch_not_taken)
01638 {
01639   // -- Remove all blocks that are dominated by the branch not taken,
01640   // unless they are also dominated by the branch taken.
01641 
01642   int size = _forward_basicblock_order.size();
01643 
01644   for (int i = 0; i < size; i++) {
01645 
01646     basicblockNode * block = _forward_basicblock_order[i];
01647 
01648     if (Dominators::dominates(branch_not_taken, block) &&
01649         ( ! Dominators::dominates(cond, block)))
01650       {
01651         // -- Figure out where the bit should be
01652 
01653         int position = block_position(block, Forward);
01654 
01655         // -- Remove it from the list
01656 
01657         _worklist.remove_block(position);
01658 
01659         // -- Add it to the skip list
01660 
01661         _blocks_to_skip.insert(block);
01662       }
01663   }
01664 
01665   // -- Add the conditional block itself to the list: this fixes the "if"
01666   // with no else problem.
01667 
01668   _blocks_to_skip.insert(cond);
01669 }
01670 
01675 void procedureInfo::update_conditional_worklist(basicblockNode * block,
01676                                                 bool has_truth_value,
01677                                                 bool which_branch)
01678 {
01679   if (pointerOptions::Verbose)
01680     cout << "Conditional analysis:" << endl;
01681 
01682   if (has_truth_value &&
01683       (block->succs().size() == 2)) {
01684 
01685     // -- Get the two branches
01686 
01687     true_branch_map_p p = _true_branches.find(block);
01688     if (p == _true_branches.end()) {
01689       cout << "ERROR: at basic block " << block->dfn() << " could not find true branch" << endl;
01690       return;
01691     }
01692 
01693     basicblockNode * true_branch = (*p).second;
01694 
01695     basicblockNode * false_branch;
01696     basicblockNode * one = block->succs().front();
01697     basicblockNode * two = block->succs().back();
01698 
01699     if (true_branch == one)
01700       false_branch = two;
01701     else
01702       false_branch = one;
01703   
01704     // -- One of the branch is definitely taken...
01705 
01706     basicblockNode * branch_taken = 0;
01707     basicblockNode * branch_not_taken = 0;
01708 
01709     if (which_branch) {
01710 
01711       // -- Only execute the true branch: remove the false branch blocks
01712 
01713       branch_taken = true_branch;
01714       branch_not_taken = false_branch;
01715     }
01716     else {
01717 
01718       // -- Only execute the false branch: remove the true branch blocks
01719     
01720       branch_taken = false_branch;
01721       branch_not_taken = true_branch;
01722     }
01723 
01724     // -- Only add the edge for the taken branch
01725 
01726     cfg_edge_pair edge(block, branch_taken);
01727     _active_edges.insert(edge);
01728 
01729     if (pointerOptions::Verbose) {
01730       cout << "  + Add edge: " << block->dfn() << " -> " << branch_taken->dfn() << endl;
01731       cout << "    (skipping: " <<  block->dfn() << " -> " << branch_not_taken->dfn() << ")" << endl;
01732     }
01733 
01734     // -- Remove the blocks that make up the false branch, if it's not
01735     // active
01736 
01737     cfg_edge_pair edge_not_taken(block, branch_not_taken);
01738     cfg_edge_set_p q = _active_edges.find(edge_not_taken);
01739 
01740     if (q == _active_edges.end())
01741       remove_branch_blocks(block, branch_taken, branch_not_taken);
01742   }
01743   else {
01744 
01745     if (pointerOptions::Verbose)
01746       cout << "  - No constant branch: add all edges:" << endl;
01747 
01748     // -- Can't tell which branch, or not branch at all: add all the
01749     // outgoing edges
01750 
01751     for (basicblock_list_p p = block->succs().begin();
01752          p != block->succs().end();
01753          ++p)
01754       {
01755         basicblockNode * succ = *p;
01756 
01757         cfg_edge_pair edge(block, succ);
01758         _active_edges.insert(edge);
01759 
01760         if (pointerOptions::Verbose)
01761           cout << "  + Add edge: " << block->dfn() << " -> " << succ->dfn() << endl;
01762       }
01763   }
01764 }
01765 
01766 
01767 int procedureInfo::block_position(basicblockNode * block, Direction dir)
01768 {
01769   // -- Choose which work list ordering, based on the direction
01770 
01771   worklist_order_map & ordering = (dir == Forward) ? _forward_worklist_order : _backward_worklist_order;
01772 
01773   // -- Look for the block and return it's position
01774 
01775   worklist_order_map_p p = ordering.find(block);
01776   if (p == ordering.end()) {
01777 
01778     cout << "---------------------------------------------------------" << endl;
01779     cout << "Looking for block: " << block << endl;
01780     output_context oc(cout);
01781     block->output(oc, (Node *)0);
01782 
01783     cout << "---------------------------------------------------------" << endl;
01784     cout << "Found:" << endl;
01785 
01786     for (p = ordering.begin();
01787          p != ordering.end();
01788          ++p)
01789       {
01790         basicblockNode * bb = (*p).first;
01791 
01792         cout << bb << endl;
01793         bb->output(oc, (Node *)0);
01794       }
01795 
01796     return -1;
01797   }
01798   else
01799     return (*p).second;
01800 }
01801 
01802 basicblockNode * procedureInfo::block_at(int position, Direction dir)
01803 {
01804   if (dir == Forward)
01805     return _forward_basicblock_order[position];
01806   else
01807     return _backward_basicblock_order[position];
01808 }
01809 
01810 void procedureInfo::print(ostream & out)
01811 {
01812   out << "Procedure: " << _proc->decl()->name() << endl;
01813 }
01814 
01820 void procedureInfo::stats(ostream & out)
01821 {
01822   out << std::setw(20) << _proc->decl()->name().c_str();
01823 
01824   if (is_context_insensitive())
01825     out << std::setw(6) << "true";
01826   else
01827     out << std::setw(6) << "false";
01828 
01829   if (_is_recursive)
01830     out << std::setw(6) << "true";
01831   else
01832     out << std::setw(6) << "false";
01833 
01834   out << std::setw(8) << _callsites.size();
01835   out << std::setw(8) << _external_inputs.size();
01836   out << std::setw(8) << _external_outputs.size();
01837   out << std::setw(8) << _ancestors.size();
01838   out << std::setw(8) << _calls.size();
01839 
01840   char temp[100];
01841   sprintf(temp, "%10.4f %10.4f", self_timer(), total_timer());
01842 
01843   out << std::setw(20) << temp;
01844 
01845   out << std::setw(8) << count_calling_contexts();
01846   out << std::setw(8) << procedure_size();
01847 
01848   out << endl;
01849 
01850   /*
01851   for (procedureinfo_set_p p = _calls.begin();
01852        p != _calls.end();
01853        ++p)
01854     {
01855       procedureInfo * called =*p;
01856       out << "      " << called->proc()->decl()->name();
01857     }
01858   */
01859 }
01860 
01865 int procedureInfo::count_calling_contexts()
01866 {
01867   proc_int_map counts;
01868 
01869   /*
01870   cout << "COUNT " << qualified_name() << endl;
01871   string indent(" ");
01872   */
01873   return count_calling_contexts_rec(counts, (stmtNode *)0);
01874 }
01875 
01880 int procedureInfo::count_calling_contexts_rec(proc_int_map & counts,
01881                                               stmtNode * callsite)
01882 {
01883   // -- Special case: always return 1 for recursive procedures.
01884 
01885   if (is_recursive()) {
01886     /*
01887     cout << indent << " + " << qualified_name() << " = 1 (recursive)";
01888     if (callsite)
01889       cout << " at " << callsite->coord() << endl;
01890     else
01891       cout << " (no callsite)" << endl;
01892     */
01893     return 1;
01894   }
01895 
01896   // -- If we've already computed the count for this procedure, then return
01897   // it immediately
01898 
01899   proc_int_map_p p = counts.find(this);
01900   if (p !=  counts.end()) {
01901     /*
01902     cout << indent << " + " << qualified_name() << " = " << (*p).second << " (already seen)";
01903     if (callsite)
01904       cout << " at " << callsite->coord() << endl;
01905     else
01906       cout << " (no callsite)" << endl;
01907     */
01908     return (*p).second;
01909   }
01910 
01911   // -- Get the list of call sites
01912 
01913   const callsite_map & sites = callsites();
01914 
01915   // -- Base-case: main has only one context
01916 
01917   if (sites.empty())
01918     return 1;
01919 
01920   // -- For all other procedures, the number of contexts is the sum of the
01921   // number of contexts for each call site. We have to be careful here: a
01922   // callsite in this situation is not a stmtLocation; it's a particular
01923   // stmtNode. So, first build a list of actual call sites.
01924 
01925   typedef pair< procedureInfo *, stmtNode * > call_site_pair;
01926   typedef set< call_site_pair> stmt_set;
01927   typedef stmt_set::iterator stmt_set_p;
01928 
01929   stmt_set stmts;
01930 
01931   for (callsite_map_cp q = sites.begin();
01932        q != sites.end();
01933        ++q)
01934     {
01935       procedureInfo * caller = (*q).second;
01936       stmtNode * stmt = ((*q).first)->stmt();
01937 
01938       call_site_pair call_site(caller, stmt);
01939       stmts.insert(call_site);
01940     }
01941 
01942   // string indent2 = indent + "  ";
01943   int total = 0;
01944 
01945   counts[this] = total;
01946 
01947   for (stmt_set_p w = stmts.begin();
01948        w != stmts.end();
01949        ++w)
01950     {
01951       procedureInfo * caller = (*w).first;
01952       stmtNode * call_site = (*w).second;
01953 
01954       total += caller->count_calling_contexts_rec(counts, call_site);
01955     }
01956 
01957   // -- Store the count and return it
01958 
01959   counts[this] = total;
01960 
01961   /*
01962   cout << indent << " + " << qualified_name() << " = " << total;
01963   if (callsite)
01964     cout << " at " << callsite->coord() << endl;
01965   else
01966     cout << " (no callsite)" << endl;
01967   */
01968 
01969   return total;
01970 }
01971 
01977 int procedureInfo::procedure_size()
01978 {
01979   blockNode * body = proc()->body();
01980 
01981   int total = 0;
01982 
01983   for (stmt_list_p p = body->stmts().begin();
01984        p != body->stmts().end();
01985        ++p)
01986     {
01987       basicblockNode * bb = (basicblockNode *) (*p);
01988 
01989       total += bb->stmts().size();
01990     }
01991 
01992   return total;
01993 }
01994 
01995            
01996 

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