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  

memoryblock.cc

Go to the documentation of this file.
00001 // $Id: memoryblock.cc,v 1.33 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 "memorymodel.h"
00040 #include "memoryblock.h"
00041 #include "unification.h"
00042 
00043 // ------------------------------------------------------------
00044 // Constructor
00045 // NOTE: New memoryBlocks should only be created by the
00046 //       memoryModel class.
00047 // ------------------------------------------------------------
00048 
00049 int memoryBlock::memoryblock_count = 0;
00050 
00051 
00052 // --- Constructor for objects that have declarations
00053 
00054 memoryBlock::memoryBlock(declNode * decl, bool synthetic,
00055                          memoryBlock * container,
00056                          procNode * local_to)
00057   : _container(container),
00058     Defs(),
00059     Uses(),
00060     _parameter_assignments(),
00061     _current_use(0),
00062     _current_def(0),
00063     _components(),
00064     _decl(decl),
00065     _synthetic_decl(synthetic),
00066     _write_protected(false),
00067     _is_array(false),
00068     _is_array_element(false),
00069     _is_indexed(false),
00070     _is_allocation_object(false),
00071     _flow_sensitive(true),
00072     _unify(false), // TB_unify
00073     _unifytype(0),
00074     _single_assignment(true),
00075     _is_return_value(false),
00076     _local_to(local_to),
00077     // _name(),
00078     _allocation_site(0),
00079     // _initializer_def(0),
00080     _allocation_object(0),
00081     // _only_def(0),
00082     // _only_use(0),
00083     _input_to(),
00084     _destructive_assignments(),
00085     _complicit_assignments(),
00086     property(0),
00087     property_blocks()
00088 {
00089   // If this new memoryBlock is contained by another, and that container is
00090   // a multiply-object representative, then set the flags on this block as
00091   // well.
00092 
00093   if (container) {
00094     if (container->is_indexed())
00095       set_indexed();
00096 
00097     if (container->is_heap_object())
00098       set_heap_object(container->allocation_site());
00099 
00100     if (container->is_return_value())
00101       set_return_value();
00102   }
00103 
00104   memoryblock_count++;
00105 }
00106 
00107 memoryBlock::~memoryBlock()
00108 {
00109   if (_synthetic_decl && ! is_heap_object())
00110     delete _decl;
00111 
00112   clear();
00113 
00114   memoryblock_count--;
00115 
00116   if(unifyType()) unifyType()->block(NULL); // TB_unify
00117 }
00118 
00119 void memoryBlock::clear()
00120 {
00121   if (is_array() && _current_def) {
00122     // want to delete _current_def, but in unify mode, possible that it it also
00123     // in Defs. Check to prevent double deletion.
00124     bool ok_delete = true;
00125     if(unifyType()) {
00126       const memorydef_list & defs = Defs.def_list();
00127       for(memorydef_list_cp d=defs.begin(); d!=defs.end(); d++)
00128         if(d->def == _current_def)
00129         { ok_delete = false; break; }
00130     }
00131 
00132     if(ok_delete)
00133       delete _current_def;
00134   }
00135 
00136   Defs.clear();
00137   Uses.clear();
00138 
00139 
00140   /*
00141   if (_initializer_def) {
00142     delete _initializer_def;
00143     _initializer_def = 0;
00144   }
00145   */
00146 }
00147 
00148 void memoryBlock::stats()
00149 {
00150   cout << "  memoryBlock : " << memoryblock_count << " objects x " 
00151        << sizeof(memoryBlock) << " bytes = " << memoryblock_count * sizeof(memoryBlock) 
00152        << " bytes. " << endl;
00153 
00154   FieldNames.stats();
00155 }
00156 
00157 // ------------------------------------------------------------
00158 //   Memory block operators
00159 // ------------------------------------------------------------
00160 
00161 // --- Managing uses and defs
00162 
00163 // def_at: Create a memoryDef for the given location, inserting it
00164 // into the orderedDefs list in the proper place. If an entry already
00165 // exists for the location, just return that one.
00166 
00167 memoryDef * memoryBlock::def_at(Location * where, bool & is_new)
00168 {
00169   //  if (name() == "global") {
00170   //    memoryAccess::Verbose = true;
00171   //    cout << "Def at " << name() << endl;
00172   //  }
00173 
00174   if (write_protected())
00175     assert(0);
00176 
00177   if (memoryAccess::Verbose)
00178     cout << "memoryBlock::def_at " << name() << endl;
00179 
00180   if ( ! is_array()) {
00181 
00182     // -- Check flow sensitivity
00183 
00184     if (is_flow_sensitive()) {
00185 
00186       // -- Flow sensitive: create a def at the given location
00187 
00188       _current_def = Defs.make_def_at(where, this, is_new);
00189     }
00190     else {
00191 
00192       // -- Flow insensitive: the only def is the one at main
00193 
00194       if ( ! _current_def)
00195         _current_def = Defs.make_def_at(where, this, is_new);
00196       else
00197         is_new = false;
00198     }
00199 
00200     // -- For the adaptive algorithm, record if there are multiple
00201     // different defs (even if we don't store them).
00202 
00203     Location * cur_where = _current_def->where();
00204 
00205     if (_single_assignment) {
00206       if (cur_where->kind() != where->kind())
00207         _single_assignment = false;
00208       else {
00209         if (where->kind() == Location::Statement) {
00210           stmtLocation * one = (stmtLocation *) cur_where;
00211           stmtLocation * two = (stmtLocation *) where;
00212 
00213           if (one->stmt() != two->stmt())
00214             _single_assignment = false;
00215         }
00216         if (where->kind() == Location::Procedure) {
00217           procLocation * one = (procLocation *) cur_where;
00218           procLocation * two = (procLocation *) where;
00219 
00220           if (one->proc() != two->proc())
00221             _single_assignment = false;
00222         }
00223         if (where->kind() == Location::BasicBlock)
00224           _single_assignment = false;
00225       }
00226     }
00227   }
00228   else {
00229 
00230     // -- Array objects: just set up the pointer to the elements
00231 
00232     setup_array_def();
00233     is_new = false;
00234   }
00235 
00236   //  memoryAccess::Verbose = false;
00237 
00238   if (_write_protected)
00239     cout << "WARNING: Def of write-protected object \"" << name() << "\"" << endl;
00240 
00241   //  if (name() == "inName_el_1")
00242   //    cout << "DEF AT = " << * (_current_def->where()) << endl;
00243 
00244   return _current_def;
00245 }
00246 
00247 // nearest_def_at: Given a program location, find the nearest strictly
00248 // dominating assignment. If none exists, return null (not a good
00249 // situation).
00250 
00251 memoryDef * memoryBlock::nearest_def_at(Location * where)
00252 {
00253   memoryDef * def =  0;
00254 
00255   if ( ! is_array()) {
00256 
00257     // -- Check flow sensitivity
00258 
00259     if (is_flow_sensitive()) {
00260 
00261       // -- Flow sensitive: find the dominating definition
00262 
00263       def = Defs.find_strictly_dominating_def(where);
00264     }
00265     else {
00266 
00267       // -- Flow insensitive: return the only def
00268 
00269       bool is_new;
00270       if ( ! _current_def)
00271         _current_def = Defs.make_def_at(procLocation::main(), this, is_new);
00272 
00273       def = _current_def;
00274     }
00275   }
00276   else
00277     def = setup_array_def();
00278 
00279   //  memoryAccess::Verbose = false;
00280 
00281   return def;
00282 }
00283 
00288 /*
00289 memoryDef * memoryBlock::nearest_def_at(Location * where,
00290                                         const procedurecall_stack & callstack)
00291 {
00292   memoryDef * def = nearest_def_at(where);
00293   procedureInfo * current_info = 0;
00294   stmtLocation * current_callsite = 0;
00295 
00296   // -- Move up the call stack until we find a reaching def
00297 
00298   procedurecall_stack_crp stack_p = callstack.rbegin();
00299 
00300   while ( ! def &&
00301           (stack_p != callstack.rend()))
00302     {
00303       current_callsite = (*stack_p).first;
00304       current_info = (*stack_p).second;
00305 
00306       // -- Short-circuit: don't both looking for a non-local def of a local
00307       // variable
00308 
00309       if (local_to() == current_info->proc())
00310         return 0;
00311 
00312       // -- See if there is a def that reaches the current callsite
00313 
00314       if (current_callsite)
00315         def = nearest_def_at(current_callsite);
00316 
00317       // -- Move up the call stack
00318 
00319       stack_p++;
00320     }
00321 
00322   return def;
00323 }
00324 */
00325 
00326 // use_at : Create a memoryUse for the given location and add it to
00327 // the Uses map. If one already exists, just return that one.
00328 
00329 // Special case: for arrays, we will set the reaching def to the special
00330 // initializer def, that way we can treat things like "*A" and "A[0]"
00331 // uniformly.
00332 
00333 memoryUse * memoryBlock::use_at(Location * where)
00334 {
00335   if (memoryAccess::Verbose)
00336     cout << "memoryBlock::use_at " << name() << endl;
00337 
00338   // cout << "Use at " << name() << endl;
00339 
00340   // -- Check flow sensitivity
00341 
00342   if (is_flow_sensitive()) {
00343 
00344     // -- Flow sensitive: make a use at the given location
00345 
00346     _current_use = Uses.make_use_at(where, this);
00347   }
00348   else {
00349 
00350     // -- Flow insensitive: there is only one use at the end of the main function
00351 
00352     if ( ! _current_use)
00353       _current_use = Uses.make_use_at(procLocation::main()->last(), this);
00354   }
00355 
00356   // -- Arrays are special: make sure all uses have a single reaching def
00357   // that points to the elements.
00358 
00359   if (is_array())
00360     memoryDef * def = setup_array_def();
00361 
00362   return _current_use;
00363 }
00364 
00365 memoryDef * memoryBlock::last_def_at(basicblockLocation * block)
00366 {
00367   memoryDef * def = 0;
00368 
00369   if (! is_array()) {
00370 
00371     // -- Check flow sensitivity
00372 
00373     if (is_flow_sensitive()) {
00374 
00375       // -- Flow sensitive: find the def that dominates the last statement
00376 
00377       stmtLocation * last = block->last();
00378 
00379       def = Defs.find_dominating_def(last);
00380     }
00381     else {
00382 
00383       // -- Flow insensitive: return the only def
00384 
00385       bool is_new;
00386       if ( ! _current_def)
00387         _current_def = Defs.make_def_at(procLocation::main(), this, is_new);
00388 
00389       def = _current_def;
00390     }
00391   }
00392   else
00393     def = setup_array_def();
00394 
00395   return def;
00396 }
00397 
00398 memoryDef *  memoryBlock::find_def_at(Location * where)
00399 {
00400   if ( ! is_array()) {
00401 
00402     // -- Check flow sensitivity
00403 
00404     if (is_flow_sensitive()) {
00405 
00406       // -- Flow sensitive: see if there is a def at the location
00407 
00408       return Defs.find_def(where);
00409     }
00410     else {
00411 
00412       // -- Flow insensitive: return the only def
00413 
00414       return _current_def;
00415     }
00416   }
00417   else
00418     return setup_array_def();
00419 }
00420 
00426 memoryUse * memoryBlock::find_use_at(Location * where)
00427 {
00428   // -- Check flow sensitivity
00429 
00430   if (is_flow_sensitive()) {
00431 
00432     // -- Flow sensitive: see if there is a use at the location
00433 
00434     return Uses.find_use(where);
00435   }
00436   else {
00437 
00438     // -- Flow insensitive: return the only use
00439     
00440     return _current_use;
00441   }
00442 }
00443 
00444 
00449 void memoryBlock::find_uses_at(Location * where, memoryuse_set & uses)
00450 {
00451   Uses.find_uses_at(where, uses);
00452 }
00453 
00460 void memoryBlock::add_parameter_assignment(procNode * proc, stmtLocation * callsite,
00461                                            memoryBlock * block)
00462 {
00463   memoryblock_set temp;
00464   temp.insert(block);
00465 
00466   _parameter_assignments[proc][callsite] = temp;
00467 }
00468 
00475 void memoryBlock::add_parameter_assignment(procNode * proc, stmtLocation * callsite,
00476                                            memoryblock_set & blocks)
00477 {
00478   _parameter_assignments[proc][callsite] = blocks;
00479 }
00480 
00481 void memoryBlock::apply_weak_update(Location * current,
00482                                     memoryDef * previous_def,
00483                                     memoryuse_set & uses)
00484 {
00485   // -- We must have a current def.
00486 
00487   memoryDef * block_def = current_def();
00488 
00489   // -- Mark the def as weak
00490   
00491   block_def->set_weak(true);
00492 
00493   // -- Collect the previous pointer values
00494 
00495   if (previous_def)
00496     block_def->add_pointers(previous_def->points_to());
00497 
00498   // -- We will also consider this to be a "use" of the old
00499   // value. This is necessary to make liveness analysis work
00500   // correctly (and probably other analyses as well).
00501             
00502   memoryUse * weak_use = use_at(current);
00503 
00504   uses.insert(weak_use);
00505 
00506   weak_use->reaching_def(previous_def);
00507   weak_use->set_weak(true);
00508 }
00509 
00510 static unsigned long int preds_size_histogram[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
00511 static unsigned long int preds_size_count = 0;
00512 
00513 // Create the set of merge uses (the inputs to the phi function) at the
00514 // given merge point.
00515 
00516 void memoryBlock::setup_merge_uses_at(basicblockLocation * merge_location,
00517                                       memoryDef * reaching_def,
00518                                       basicblock_set & predecessors)
00519 {
00520   //  if (name() == "outName_el_3")
00521   //    cout << "    Setup Merge " << name() << endl;
00522 
00533   // --- Current block
00534 
00535   basicblockNode * basicblock = merge_location->block();
00536 
00537   // --- Look up (or create) the set of uses for the merge (one for
00538   // each control-flow predecessor).
00539 
00540   const pred_use_map & pred_uses = Uses.make_merge_uses_at(merge_location, this);
00541 
00542   for (basicblock_set_p p = predecessors.begin();
00543        p != predecessors.end();
00544        ++p)
00545     {
00546       basicblockNode * predecessor = *p;
00547 
00548       // --- Find the merge-point use corresponding to the given
00549       // predecessor.
00550 
00551       pred_use_map_cp cp = pred_uses.find(predecessor);
00552       memoryUse * use = (*cp).second;
00553 
00554       // --- Set the reaching def field, and indicate NOT to search
00555       // for it later when the merge point is actually encountered.
00556 
00557       memoryDef * old_def = use->reaching_def();
00558       if (( ! old_def) ||
00559           (old_def && Location::strictly_dominates(old_def->where(), reaching_def->where()))) {
00560 
00561         use->reaching_def(reaching_def);
00562         use->search_for_def(false);
00563       }
00564 
00565       /*
00566       if (name() == "outName_el_3") {
00567         cout << "      at " << * merge_location << " through pred " << predecessor->dfn() << endl;
00568 
00569         if (( ! old_def) ||
00570             (old_def && Location::strictly_dominates(old_def->where(), reaching_def->where()))) {
00571           cout <<   "      take trigger def at " << * (reaching_def->where()) << endl;
00572           if (old_def) 
00573             cout << "          over old def at " << * (old_def->where()) << endl;
00574           else
00575             cout << "         (no old def)" << endl;    
00576         }
00577         else {
00578           cout <<   "      keep old def at " << * (old_def->where()) << endl <<
00579                     "  over trigger def at " << * (reaching_def->where()) << endl;
00580         }
00581       } */
00582     }
00583 }
00584 
00585 // merge_uses_at : (When a merge point is encountered) Look up the set
00586 // of uses for a merge point (one for each control-flow
00587 // predecessor). This set will already have been created by calls to
00588 // setup_merge_uses_at above. The purpose of this function is simply
00589 // to fill in any uses that don't have reaching definitions yet.
00590 
00591 void memoryBlock::merge_uses_at(basicblockLocation * where,
00592                                 memoryuse_list & uses,
00593                                 cfg_edge_set & active_edges,
00594                                 memoryDef * dominating_def,
00595                                 bool computePointers)
00596 {
00597   /*
00598   bool flag = false;
00599   if (decl()->name() == "nHeap") {
00600     flag = true;
00601     memoryAccess::Verbose = true;
00602   }
00603   */
00604 
00605   // cout << " MERGE " << name() << " at " << * where << endl;
00606 
00607   // cout << "    Merge " << name() << endl;
00608   
00609   // Get the uses associated with this merge point. There should be
00610   // one for each control-flow predecessor. They are returned as a map
00611   // from the particular predecessor to the use that represents it.
00612 
00613   const pred_use_map & pred_uses = Uses.make_merge_uses_at(where, this);
00614 
00615   basicblock_list & preds = where->block()->preds();
00616   const procLocation * proc_loc = where->proc_location();
00617 
00618   int size = preds.size();
00619   if (size != pred_uses.size())
00620     cerr << "ERROR: Wrong number of uses in a merge node." << endl;
00621   
00622   if (size < 2)
00623     cerr << "ERROR: Merge-point with only one predecessor." << endl;
00624 
00625   /* Debug stuff
00626   preds_size_count++;
00627   int temp = size;
00628   if (temp > 9) temp = 9;
00629   preds_size_histogram[temp]++;
00630   */
00631 
00632   // -- Get the current basic block (where the merge is occuring)
00633 
00634   basicblockNode * basicblock = where->block();
00635 
00636   // -- Visit the uses
00637 
00638   if (computePointers) {
00639 
00640     // --- TRUE Hypothesis: the reaching def for all the remaining phi
00641     // uses is the def that dominates the phi node itself.
00642 
00643     // --- For each basic block predecessor
00644 
00645     int skipped = 0;
00646 
00647     for (pred_use_map_cp cp = pred_uses.begin();
00648          cp != pred_uses.end();
00649          ++cp) 
00650       {
00651         basicblockNode * predecessor = (*cp).first;
00652         memoryUse * use = (*cp).second;
00653 
00654         // -- Conditional analysis
00655 
00656         if (pointerOptions::Conditional_analysis) {
00657           
00658           // -- Set a use to "inactive" if its incoming edge is not active.
00659 
00660           cfg_edge_pair edge(predecessor, basicblock);
00661           if (active_edges.find(edge) == active_edges.end()) {
00662 
00663             // -- This use is ignored because it comes from a branch that
00664             // we're not executing.
00665 
00666             use->set_inactive();
00667 
00668             if (pointerOptions::Verbose)
00669               cout << "MERGE: skipping input of " << name() << " from inactive edge "
00670                    << predecessor->dfn() << " -> " << basicblock->dfn() << endl;
00671           }
00672           else {
00673 
00674             // -- Active use: we executed the path that it comes from
00675 
00676             use->set_active();
00677 
00678             // -- Find its reaching def
00679 
00680             if (use->search_for_def())
00681               use->reaching_def(dominating_def);
00682 
00683             // -- Add to the return results
00684 
00685             uses.push_back(use);
00686           }
00687         }
00688         else {
00689 
00690           // -- Regular analysis
00691 
00692           // -- This is key: any merge uses that don't already have their
00693           // reaching defs set (and have the search_for_def flag true) are
00694           // reached by the def that dominated the merge point itself.
00695           
00696           if (use->search_for_def())
00697             use->reaching_def(dominating_def);
00698 
00699           // -- Add to the return results
00700 
00701           uses.push_back(use);
00702         }
00703       }
00704   }
00705   else {
00706 
00707     // We are no longer building the def-use chains, so just get the list
00708     // of uses.
00709 
00710     for (pred_use_map_cp cp = pred_uses.begin();
00711          cp != pred_uses.end();
00712          ++cp) 
00713       {
00714         memoryUse * use = (*cp).second;
00715         uses.push_back(use);
00716       }
00717   }
00718 }
00719 
00720 void memoryBlock::reset_current_def_use(Location * unused)
00721 {
00722   // -- Reset the current_use field, but only for flow-sensitive objects.
00723 
00724   if (is_flow_sensitive() &&
00725       ! is_array() && !unifyType() /* TB_unify */) {
00726     _current_use = 0;
00727     _current_def = 0;
00728   }
00729 
00730   //  if (name() == "outName_el_3")
00731   //    cout << "RES outName_el_3 " << endl;
00732 
00733   /*
00734   // -- Find the definition that reaches the procedure exit
00735 
00736   _current_def = nearest_def_at(last_stmt);
00737 
00738   if (name() == "outName_el_3") {
00739     cout << "Reset " << name() << " at " << * last_stmt << " reaching def at " << * _current_def->where() << endl;
00740   }
00741   */
00742 }
00743 
00744 void memoryBlock::set_current_def_use(Location * where)
00745 {
00746   if ( ! is_array()) {
00747 
00748     // -- Check flow sensitivity
00749 
00750     if (is_flow_sensitive()) {
00751 
00752       // -- Flow sensitive: look up def and use at the given location
00753       
00754       _current_def = Defs.find_def(where);
00755       _current_use = Uses.find_use(where);
00756     }
00757     else {
00758 
00759       // -- Flow insensitive: there is only one use and def, and we store
00760       // them in the current_use/current_def fields.
00761 
00762       //      _current_def = _only_def;
00763       //      _current_use = _only_use;
00764     }
00765   }
00766 }
00767 
00768 // ------------------------------------------------------------
00769 // Managing structure fields
00770 // ------------------------------------------------------------
00771 
00772 // Dot "." operator: retrieve a sub-component by name, assuming the
00773 // memoryBlock is a struct-like thing. If the field doesn't exist,
00774 // then create one
00775 
00776 void memoryBlock::dot(const string & field_name,
00777                       declNode * field_decl,
00778                       memoryModel & Memory,
00779                       memoryblock_set & results)
00780 {
00781   // cout << "DOT  " << name() << endl;
00782 
00783   memoryBlock * new_block = 0;
00784 
00785   // --- Map the field name using the field name database
00786 
00787   int field_num = FieldNames.get_field(field_name);
00788 
00789   // --- Try to find that component
00790 
00791   component_map_p p = _components.find(field_num);
00792 
00793   if (p == _components.end()) {
00794 
00795     // TB_unify
00796     if(Memory.unification() && !is_unify() && decl() &&
00797        (decl()->decl_location()==declNode::PROC ||
00798         decl()->no_tdef_type() && decl()->no_tdef_type()->typ() == Func))
00799       return;
00800 if(name() == "load_actions_file" && field_name=="filename") {
00801   cout << Memory.unification() << " " << is_unify() << " " << this << endl;
00802   if(decl()) {
00803     cout << decl()->name() << " loc=" << decl()->decl_location();
00804     if(decl()->no_tdef_type()) cout << " " << decl()->no_tdef_type()->typ();
00805     cout << endl;
00806   }
00807   assert(false);
00808 }
00809 
00810     // -- Create the new field, with this object as the container
00811 
00812     new_block = Memory.generate_su_field(field_name, field_decl, this);
00813 
00814     // --- Store the new field object in the parent object
00815 
00816     _components[field_num] = new_block;
00817     
00818     // --- Also, assume the owning procedure is the same as that of
00819     // the container.
00820 
00821     new_block->_local_to = _local_to;
00822 
00823     results.insert(new_block);
00824   }
00825   else {
00826 
00827     // --- Found it
00828 
00829     results.insert((*p).second);
00830   } 
00831 }
00832 
00833 void memoryBlock::set_array_element(memoryBlock * element)
00834 {
00835   // -- Store the array element in the special component position
00836 
00837   _components[FieldNameDB::ArrayField] = element;
00838 
00839   // -- Set the is_array flag
00840 
00841   _is_array = true;
00842 
00843   // --- Also, assume the owning procedure is the same as that of
00844   // the container.
00845 
00846   element->_local_to = _local_to;
00847 
00848   // -- Set the container pointer on the element
00849 
00850   element->_container = this;
00851 
00852   // -- Set the flag on the element
00853 
00854   element->_is_array_element = true;
00855 
00856   // -- Array objects are not writable
00857 
00858   if(! unifyType()) // TB_unify
00859     set_write_protected();
00860 }
00861 
00862 memoryBlock * memoryBlock::get_array_element()
00863 {
00864   // -- The array element is the special -1 field
00865 
00866   component_map_p p = _components.find(FieldNameDB::ArrayField);
00867   if (p != _components.end()) {
00868 
00869     // --- Found it
00870 
00871     return (*p).second;
00872   }
00873   else
00874     return 0;
00875 } 
00876 
00877 memoryDef * memoryBlock::setup_array_def()
00878 {
00879   // -- Make sure this special def is set up
00880 
00881   if ( ! _current_def) {
00882 
00883     // -- Make this block point to it's element in all contexts
00884 
00885     _current_def = new memoryDef(procLocation::main(), this);
00886 
00887     memoryBlock * element = get_array_element();
00888     if ( element ) {
00889 
00890       memoryblock_set temp;
00891 
00892       temp.insert(element);
00893       _current_def->add_pointers(temp);
00894     }
00895   }
00896 
00897   // -- Always make this def the reaching def.
00898   // use->reaching_def(_initializer_def);
00899 
00900   return _current_def;
00901 }
00902 
00903 // ------------------------------------------------------------
00904 //  Reachability
00905 // ------------------------------------------------------------
00906 
00907 void memoryBlock::reachable_blocks(Location * where,
00908                                    bool has_use_here,
00909                                    memoryblock_list & worklist,
00910                                    memoryblock_set & already_seen,
00911                                    memoryBlock * null)
00912 {
00913   // -- Find the nearest dominating def, if there is one
00914 
00915   memoryDef * def = 0;
00916 
00917   if (has_use_here) {
00918 
00919     // -- Already have a use: just get it's reaching def
00920 
00921     memoryUse * use = find_use_at(where);
00922     if (use)
00923       def = use->reaching_def();
00924   }
00925   else {
00926 
00927     // -- Need to compute the reaching def
00928 
00929     def = nearest_def_at(where);
00930   }
00931 
00932   if (def) {
00933 
00934     // -- Look at the reachable blocks, adding only those that haven't been
00935     // seen before.
00936 
00937     const memoryblock_set & pointers = def->points_to();
00938     for (memoryblock_set_cp p = pointers.begin();
00939          p != pointers.end();
00940          ++p)
00941       {
00942         memoryBlock * mb = *p;
00943         if ((mb != null) &&
00944             (already_seen.find(mb) == already_seen.end())) {
00945 
00946           // -- We haven't seen this one yet
00947 
00948           already_seen.insert(mb);
00949           worklist.push_back(mb);
00950         }
00951       }
00952   }
00953 
00954   // -- Add all the field components...
00955 
00956   for (component_map_p p = _components.begin();
00957        p != _components.end();
00958        ++p)
00959     {
00960       memoryBlock * mb = (*p).second;
00961       if (already_seen.find(mb) == already_seen.end()) {
00962 
00963         // -- We haven't seen this one yet
00964 
00965         already_seen.insert(mb);
00966         worklist.push_back(mb);
00967       }
00968     }
00969 }
00970 
00971 // ------------------------------------------------------------
00972 //  Heap allocation object
00973 // ------------------------------------------------------------
00974 
00975 memoryBlock * memoryBlock::get_allocation_object(memoryModel & Memory)
00976 {
00977   memoryBlock * current = this;
00978 
00979   if (pointerOptions::Verbose)
00980     cout << "    + Get allocation object for " << name() << endl;
00981 
00982   // -- Find the top-most object container
00983 
00984   while (current->_container) {
00985     if(current == current->_container) break;
00986     current = current->_container;
00987   }
00988 
00989   if (current->_allocation_object == 0) {
00990 
00991     // -- Treat it like a struct field of the object
00992 
00993     memoryBlock * alloc_object = Memory.generate_su_field(string("__alloc"),
00994                                                           (declNode *)0, this);
00995 
00996     // -- Mark it as special
00997 
00998     alloc_object->_is_allocation_object = true;
00999 
01000     // -- Inherit flow sensitivity, or look up in the list
01001 
01002     if (current->is_unify()) {
01003       if(! alloc_object->is_unify()) {
01004         pointerOptions::Unify_objects++;
01005         alloc_object->set_unify(true);
01006       }
01007       alloc_object->set_flow_insensitive();
01008     } else if (current->is_flow_sensitive())
01009       alloc_object->set_flow_sensitive();
01010     else
01011       alloc_object->set_flow_sensitivity(pointerOptions::Flow_sensitive_allocation_objects);
01012 
01013     // -- Store it on the heap object
01014 
01015     current->_allocation_object = alloc_object;
01016 
01017     if (pointerOptions::Verbose) {
01018       cout << "      -> Not found: create " << alloc_object->name();
01019       if (alloc_object->is_flow_sensitive())
01020         cout << "  (flow-sensitive)" << endl;
01021       else
01022         cout << "  (not flow-sensitive)" << endl;
01023     }
01024   }
01025 
01026   return current->_allocation_object;
01027 }
01028 
01033 memoryBlock * memoryBlock::allocation_object()
01034 {
01035   memoryBlock * current = this;
01036 
01037   // -- Find the top-most object container
01038 
01039   while (current->_container) {
01040     if(current == current->_container) break;
01041     current = current->_container;
01042   }
01043 
01044   return current->_allocation_object;
01045 }
01046 
01047 
01048 Multiplicity memoryBlock::at_allocation(Location * current,
01049                                         memoryDef * reaching_def,
01050                                         memoryblock_set & defs,
01051                                         memoryuse_set & uses,
01052                                         memoryblock_set & changes)
01053 {
01054   bool changed = false;
01055 
01056   // -- Set up a def of the heap object
01057 
01058   bool is_new;
01059   memoryDef * def = def_at(current, is_new);
01060 
01061 #ifdef COLLECT_DEFS
01062   defs.insert(this);
01063 #endif
01064 
01065   // -- If this allocation resulted in a new memoryDef instance, then it
01066   // automatically is a "change".
01067 
01068   if (is_new) {
01069     changes.insert(this);
01070     changed = true;
01071   }
01072 
01073   // -- Get the multiplicity value of the reaching definition
01074 
01075   Multiplicity reaching_multiplicity = Unallocated;
01076 
01077   if (reaching_def)
01078     reaching_multiplicity = reaching_def->multiplicity();
01079 
01080   // -- Reading the multiplicity is a use of this object
01081 
01082   memoryUse * use = use_at(current);
01083   use->reaching_def(reaching_def);
01084   uses.insert(use);
01085 
01086   // -- Save the old multiplicity value
01087 
01088   Multiplicity old_multiplicity = def->multiplicity();
01089 
01090   // -- Compute the new multiplicity value. This is essentially the
01091   // transfer function for allocation.
01092 
01093   Multiplicity new_multiplicity;
01094 
01095   switch (reaching_multiplicity) {
01096   case Unallocated:
01097   case Deallocated: new_multiplicity = Single;
01098     break;
01099   case Single:      new_multiplicity = Unbounded;
01100     break;
01101   case Bounded:     new_multiplicity = Bounded;
01102     break;
01103   case Unbounded:   new_multiplicity = Unbounded;
01104     break;
01105   default:          new_multiplicity = Error;
01106     break;
01107   }
01108 
01109   // -- Handle flow-insensitivity: in order to be safe all allocations make
01110   // the object Unbounded.
01111 
01112   if ( ! is_flow_sensitive())
01113     new_multiplicity = Unbounded;
01114 
01115   // -- Mark the def with the new value. If it changed, record this as a
01116   // change to the object.
01117     
01118   if (old_multiplicity != new_multiplicity) {
01119 
01120     def->set_multiplicity(new_multiplicity);
01121         
01122     changes.insert(this);
01123     changed = true;
01124   }
01125 
01126   // -- Print some debug info
01127 
01128   if (pointerOptions::Verbose) {
01129     cout << "  Allocate: " << _container->name() << " -- ";
01130 
01131     print_multiplicity(reaching_multiplicity, cout);
01132     cout << " -> ";
01133     print_multiplicity(new_multiplicity, cout);
01134     cout << " -- ";
01135 
01136     if (changed)
01137       cout << "changed";
01138     else
01139       cout << "unchanged";
01140 
01141     cout << endl;
01142   }
01143 
01144   return new_multiplicity;
01145 }
01146 
01147 Multiplicity memoryBlock::at_deallocation(Location * current,
01148                                           memoryDef * reaching_def,
01149                                           memoryblock_set & defs,
01150                                           memoryuse_set & uses,
01151                                           memoryblock_set & changes)
01152 {
01153   bool changed;
01154 
01155   // -- Set up a def of the heap object
01156 
01157   bool is_new;
01158   memoryDef * def = def_at(current, is_new);
01159 
01160 #ifdef COLLECT_DEFS
01161   defs.insert(this);
01162 #endif
01163 
01164   // -- If this deallocation resulted in a new memoryDef instance, then it
01165   // automatically is a "change".
01166 
01167   if (is_new) {
01168     changes.insert(this);
01169     changed = true;
01170   }
01171 
01172   // -- Get the multiplicity value of the reaching definition
01173 
01174   Multiplicity reaching_multiplicity = Unallocated;
01175 
01176   if (reaching_def)
01177     reaching_multiplicity = reaching_def->multiplicity();
01178 
01179   // -- Reading the multiplicity is a use of this object
01180 
01181   memoryUse * use = use_at(current);
01182   use->reaching_def(reaching_def);
01183   uses.insert(use);
01184 
01185   // -- Save the old multiplicity value
01186 
01187   Multiplicity old_multiplicity = def->multiplicity();
01188 
01189   // -- Compute the new multiplicity value. This is essentially the
01190   // transfer function for the deallocation.
01191 
01192   Multiplicity new_multiplicity;
01193 
01194   switch (reaching_multiplicity) {
01195   case Unallocated:
01196   case Deallocated: new_multiplicity = Unallocated;
01197     break;
01198   case Single:      new_multiplicity = Deallocated;
01199     break;
01200   case Bounded:     new_multiplicity = Bounded;
01201     break;
01202   case Unbounded:   new_multiplicity = Unbounded;
01203     break;
01204   default:          new_multiplicity = Error;
01205     break;    
01206   }
01207 
01208   // -- Handle flow-insensitivity: in order to be safe all allocations make
01209   // the object Unbounded.
01210 
01211   if ( ! is_flow_sensitive())
01212     new_multiplicity = Unbounded;
01213 
01214   // -- Mark the def with the new value. If it changed, record this as a
01215   // change to the object.
01216     
01217   if (old_multiplicity != new_multiplicity) {
01218 
01219     def->set_multiplicity(new_multiplicity);
01220         
01221     changes.insert(this);
01222     changed = true;
01223   }
01224 
01225   // -- Print some debug info
01226 
01227   if (pointerOptions::Verbose) {
01228     cout << "  Deallocate: " << _container->name() << " -- ";
01229 
01230     print_multiplicity(reaching_multiplicity, cout);
01231     cout << " -> ";
01232     print_multiplicity(new_multiplicity, cout);
01233     cout << " -- ";
01234 
01235     if (changed)
01236       cout << "changed";
01237     else
01238       cout << "unchanged";
01239 
01240     cout << endl;
01241   }
01242 
01243   return new_multiplicity;
01244 }
01245 
01246 void memoryBlock::print_multiplicity(Multiplicity m, ostream & out)
01247 {
01248   switch (m) {
01249   case Unallocated: out << "unallocated";
01250     break;
01251   case Deallocated: out << "deallocated";
01252     break;
01253   case Single: out << "single";
01254     break;
01255   case Bounded: out << "bounded";
01256     break;
01257   case Unbounded: out << "unbounded";
01258     break;
01259   case Error: out << "(error)";
01260     break;
01261   case Top: out << "(top)";
01262     break;
01263   default: out << "(unknown)";
01264     break;
01265   }
01266 }
01267 
01268 // ------------------------------------------------------------
01269 //  Manage precision analysis
01270 // ------------------------------------------------------------
01271 
01277 void memoryBlock::add_destructive_assignment(Location * where, DestructiveKind cause)
01278 {
01279   _destructive_assignments[where] = cause;
01280 
01281   if (pointerOptions::Verbose) {
01282     cout << " Monitor: add destructive assignment of " << name() << " at " << * where;
01283     switch (cause) {
01284     case Control_flow:   cout << " -- control-flow merge " << endl;
01285       break;
01286     case Parameter_pass: cout << " -- parameter pass" << endl;
01287       break;
01288     case Weak_update:    cout << " -- multiplicity weak update" << endl;
01289       break;
01290     case Additive:       cout << " -- flow-insensitive assignment" << endl;
01291       break;
01292     default: cout << " -- ERROR unknown cause" << endl;
01293       break;
01294     }
01295   }
01296 }
01297 
01303 void memoryBlock::add_complicit_assignment(Location * where, memoryblock_set & objects)
01304 {
01305   if ( ! objects.empty()) {
01306 
01307     memoryblock_set & comps = _complicit_assignments[where];
01308 
01309     // -- Loop through the objects, skipping any write-protected objects
01310     // (how could it be their fault?)
01311 
01312     for (memoryblock_set_p p = objects.begin();
01313          p != objects.end();
01314          ++p)
01315       {
01316         memoryBlock * comp = *p;
01317 
01318         if ( ! comp->write_protected())
01319           comps.insert(comp);
01320       }
01321     
01322     if (pointerOptions::Verbose) {
01323       cout << " Monitor: add complicit assignment of " << name() << " at " << * where << endl;
01324       cout << "            <= ";
01325       for (memoryblock_set_p p = objects.begin();
01326            p != objects.end();
01327            ++p)
01328         cout << (*p)->name() << " ";
01329       cout << endl;
01330     }
01331   }
01332 }
01333 
01339 void memoryBlock::add_complicit_assignment(Location * where, memoryBlock * object)
01340 {
01341   _complicit_assignments[where].insert(object);
01342 }
01343 
01352 void memoryBlock::add_to_flow_sensitive_list(flow_sensitive_set & flow_sensitive_objects)
01353 {
01354   stmtNode * the_stmt = 0;
01355   declNode * the_decl = 0;
01356   string field;
01357 
01358   if (container())
01359     field = decl()->name();
01360 
01361   // -- If it's a heap object, then the allocation site matters
01362 
01363   if (is_heap_object())
01364     the_stmt = allocation_site()->stmt();
01365 
01366   // -- Find the top-most containing object
01367 
01368   memoryBlock * cur = this;
01369   while (cur->container()) {
01370     if(cur == cur->container()) break; //TB_unify
01371     cur = cur->container();
01372   }
01373 
01374   // -- Get the declaration, if it's not synthetic
01375   
01376   if ( ! cur->is_synthetic_decl())
01377     the_decl = cur->decl();
01378 
01379   // -- Make the identifying pair
01380 
01381   FSKey key(the_stmt, the_decl, field);
01382 
01383   // -- Add it to the list
01384 
01385   flow_sensitive_set_p found = find(flow_sensitive_objects.begin(),
01386                                     flow_sensitive_objects.end(),
01387                                     key);
01388 
01389   if (found == flow_sensitive_objects.end()) {
01390     flow_sensitive_objects.push_back(key);
01391     /*
01392     cout << "NEW fs object: " << name() << " -- key is "
01393          << "(" << the_stmt << "," << the_decl << "," << field << ")" << endl;
01394     if (the_decl)
01395       cout << " declared at " << the_decl->coord() << endl;
01396     */
01397   }
01398 
01399   if (pointerOptions::Verbose) {
01400 
01401     if (found == flow_sensitive_objects.end())
01402       cout << "Adaptivity: Record block " << name() << " flow-sensitive -- key is "
01403            << "(" << the_stmt << "," << the_decl << "," << field << ")" << endl;
01404   }
01405 }
01406 
01411 bool memoryBlock::is_in_flow_sensitive_list(flow_sensitive_set & flow_sensitive_objects)
01412 {
01413   // -- Make the identifying key (same as above method)
01414 
01415   stmtNode * the_stmt = 0;
01416   declNode * the_decl = 0;
01417   string field;
01418 
01419   // -- If it's a heap object, then the allocation site matters
01420 
01421   if (is_heap_object())
01422     the_stmt = allocation_site()->stmt();
01423 
01424   if (container())
01425     field = decl()->name();
01426 
01427   // -- Find the top-most containing object
01428 
01429   memoryBlock * cur = this;
01430   while (cur->container()) {
01431     if(cur == cur->container()) break; //TB_unify
01432     cur = cur->container();
01433   }
01434 
01435   // -- Get the declaration, if it's not synthetic
01436   
01437   if ( ! cur->is_synthetic_decl())
01438     the_decl = cur->decl();
01439 
01440   // -- Make the identifying pair
01441 
01442   FSKey key(the_stmt, the_decl, field);
01443 
01444   // -- Add it to the list
01445 
01446   flow_sensitive_set_p found = find(flow_sensitive_objects.begin(),
01447                                     flow_sensitive_objects.end(),
01448                                     key);
01449 
01450   if (pointerOptions::Verbose) {
01451 
01452     if (found != flow_sensitive_objects.end()) {
01453       cout << "Adaptivity: Set block " << name();
01454 
01455       if (found != flow_sensitive_objects.end())
01456         cout << " flow-sensitive ";
01457       else
01458         cout << " flow-insensitive ";
01459     
01460       cout << "-- key is "
01461            << "(" << the_stmt << "," << the_decl << "," << field << ")" << endl;
01462     }
01463   }
01464 
01465   return (found != flow_sensitive_objects.end());
01466 }
01467 
01474 void memoryBlock::set_flow_sensitivity(flow_sensitive_set & flow_sensitive_objects)
01475 {
01476   if (pointerOptions::Flow_insensitive) {
01477 
01478     // -- See if it's in the list
01479 
01480     if (is_in_flow_sensitive_list(flow_sensitive_objects)) {
01481 
01482       // -- Found: override the default
01483 
01484       set_flow_sensitive();
01485     }
01486     else {
01487 
01488       // -- Not found; inherit from the container, or just default
01489 
01490       /* NO, now we handle structure fields.
01491       if (container()) {
01492         if (container()->is_flow_sensitive())
01493           set_flow_sensitive();
01494         else
01495         set_flow_insensitive();
01496         }
01497         else
01498       */
01499 
01500       set_flow_insensitive();
01501     }
01502   }
01503   else {
01504 
01505     // -- Flow sensitive mode
01506 
01507     set_flow_sensitive();
01508   }
01509 }
01510 
01511 
01513 void memoryBlock::add_to_non_unify_list(UnifyTypes & non_unify_types)
01514 {
01515   if (unifyType()) {
01516     non_unify_types.insert(unifyType());
01517 
01518     if (pointerOptions::Verbose) {
01519       cout << "Adaptivity: Record block " << name() << " non-unify\n";
01520     }
01521   }
01522 }
01523 
01528 void memoryBlock::set_unification(UnifyTypes & non_unify_types) {
01529   if (! pointerOptions::Unification) {
01530 
01531     // -- See if it's in the list
01532 
01533     if (! unifyType() ||
01534         memoryModel::is_in_non_unify_list(non_unify_types, unifyType())) {
01535 
01536       // -- Found: override the default
01537 
01538       set_unify(false);
01539       _unifytype = NULL; // so that if set_unification() is called again on
01540                          // this object, we can skip is_in_non_unify_list().
01541     }
01542     else {
01543       if(! is_unify()) {
01544         pointerOptions::Unify_objects++;
01545         set_unify(true);
01546       }
01547     }
01548 
01549     if (pointerOptions::Verbose) {
01550       cout << "Adaptivity: Set block " << name();
01551 
01552       if (is_unify())
01553         cout << " as unified ";
01554       else
01555         cout << " as non-unified ";
01556       cout << endl;
01557     }
01558   }
01559   else {
01560 
01561     // -- Unify mode
01562 
01563     if(! is_unify() && unifyType()) {
01564       set_unify(true);
01565       pointerOptions::Unify_objects++;
01566     }
01567   }
01568 }
01569 
01570 
01571 // ------------------------------------------------------------
01572 
01577 memoryBlock * memoryBlock::top_most_container()
01578 {
01579   memoryBlock * temp = this;
01580 
01581   while (temp->_container) {
01582     if(pointerOptions::Unification && temp == temp->_container) break;
01583     temp = temp->_container;
01584   }
01585 
01586   if(is_unify() && decl() && decl()->type()) {
01587     // debug. type()->not annotated var. e.g. annotated global var may have a
01588     // field but it won't have container.
01589     memoryblock_set tops = top_most_containers();
01590     if(tops.find(temp) == tops.end()) {
01591       cout << "this " << name();
01592       if(unifyType()) cout << " " << *unifyType();
01593       cout << "\ntemp " << name() << endl;
01594       cout << "tops: ";
01595       for(memoryblock_set_p t=tops.begin(); t!=tops.end(); t++)
01596         cout << (*t)->name() << " " << *(*t)->unifyType() << endl;
01597     }
01598     assert(tops.find(temp) != tops.end());
01599   }
01600 if(is_unify()) cout << name() << endl;
01601   assert(! is_unify()); // should not use this function in this mode
01602   return temp;
01603 }
01604 
01605 memoryblock_set memoryBlock::containers() const {
01606   memoryblock_set result;
01607   if(unifyType()) {
01608     set<Unify_ECR*> parents;
01609     switch(unifyType()->objTyp()) {
01610       case BOTTOM: break;
01611       case BLANK: parents = unifyType()->blank()->p.parents(); break;
01612       case SIMPLE: parents = unifyType()->simple()->p.parents(); break;
01613       case STRUCTURE: parents = unifyType()->structure()->p.parents(); break;
01614       case OBJECT: parents = unifyType()->object()->p.parents();
01615     }
01616     for(set<Unify_ECR*>::iterator p=parents.begin(); p!=parents.end(); p++)
01617       if((*p)->type()->block())
01618         result.insert((*p)->type()->block());
01619   }
01620 #define verify_container
01621 #ifdef verify_container
01622   if(container()) {
01623     if(result.find(container()) == result.end()) {
01624       cout << "this " << name() << endl;
01625       if(unifyType()) cout << *unifyType() << endl;
01626       cout << "container " << container()->name() << endl;
01627       if(container()->unifyType()) cout << *container()->unifyType() << endl;
01628     }
01629     assert(result.find(container()) != result.end()); // ???
01630   }
01631 #endif
01632   return result;
01633 } // containers
01634 
01635 
01636 memoryblock_set memoryBlock::top_most_containers() {
01637   if(!unifyType()) {
01638     if(is_allocation_object() || property)
01639       return container()->top_most_containers();
01640     if(decl()->decl_location() == declNode::ENUM ||
01641        decl()->type() && decl()->type()->typ() == Func) {
01642       memoryblock_set r;
01643       r.insert(this);
01644       return r;
01645     }
01646     if(decl()->type() && decl()->no_tdef_type()->typ() == Ptr &&
01647        decl()->no_tdef_type()->no_tdef_type()->typ() == Func ||
01648        !decl()->type() /* annotated variable */ ) {
01649       if(container()) return container()->top_most_containers();
01650       memoryblock_set r;
01651       r.insert(this);
01652       return r;
01653     }
01654     cout << this << " " << name() << endl;
01655     if(decl()) cout << decl()->name() << decl()->coord() << endl;
01656     if(local_to()) cout << "local_to " << local_to()->decl()->name() << endl;
01657     assert(false);
01658   }
01659   memoryblock_set visited;
01660 if(pointerOptions::Verbose)
01661 cout << "top_most_containers on " << name() << endl;
01662   return top_most_containers(visited);
01663 } // top_most_containers
01664 
01665 
01666 memoryblock_set memoryBlock::top_most_containers(memoryblock_set &visited) {
01667   if(visited.find(this) != visited.end()) return memoryblock_set();
01668   visited.insert(this);
01669 if(pointerOptions::Verbose)
01670 cout << "top_most_containers (helper) on " << name() << endl;
01671   memoryblock_set parents = containers(),
01672                   result;
01673   for(memoryblock_set_p p=parents.begin(); p!=parents.end(); p++) {
01674     memoryblock_set more = (*p)->top_most_containers(visited);
01675     result.insert(more.begin(), more.end());
01676   }
01677   if(parents.empty()) result.insert(this);
01678   else if(result.empty()) { // cycle/dag detected
01679     if(parents.size() == 1 && *parents.begin() == this) result = parents;
01680     /*else {
01681       cout << "I am " << name() << " " << *unifyType() << "\nparents:\n";
01682       for(memoryblock_set_p p=parents.begin(); p!=parents.end(); p++) {
01683         cout << (*p)->name();
01684         if((*p)->unifyType()) cout << " " << *(*p)->unifyType();
01685         cout << endl;
01686       }
01687       assert(false); // what to do?? TBD
01688     }*/
01689   }
01690 if(pointerOptions::Verbose)
01691 cout << "top_most_containers on " << name() <<" returns "<< result.size()<<endl;
01692   return result;
01693 } // top_most_containers (helper)
01694 
01695 // ------------------------------------------------------------
01696 // Def use chains
01697 // ------------------------------------------------------------
01698 
01703 void memoryBlock::def_uses(memoryDef * def,
01704                            memoryuse_list & uses)
01705 {
01706   Uses.def_uses(def, uses);
01707 }
01708 
01709 // --- Update the def-use chains (only performed once at the end of
01710 // analysis by the memoryModel).
01711 
01712 void memoryBlock::update_def_use_chains()
01713 {
01714   Uses.update_def_use_chains();
01715 }
01716 
01717 // ------------------------------------------------------------
01718 // Prune uses and defs
01719 // ------------------------------------------------------------
01720 
01721 void memoryBlock::prune_defs_uses()
01722 {
01723   Defs.prune(Uses);
01724 }
01725 
01726 // ------------------------------------------------------------
01727 // Scoping
01728 // ------------------------------------------------------------
01729 
01730 // Return true if the given memory-block is "in-scope": that is, it is
01731 // variable that is local to a particular procedure and that procedure
01732 // is in the given call stack.
01733 
01734 bool memoryBlock::in_scope(basicblockLocation * where) const
01735 {
01736   if ( _local_to == 0)
01737     return true;
01738 
01739   const procLocation * cur = where->proc_location();
01740   while (cur) {
01741     if (cur->proc() == _local_to)
01742       return true;
01743     cur = cur->parent_proc();
01744   }
01745 
01746   return false;
01747 }
01748 
01749 // ------------------------------------------------------------
01750 // Printing and debug
01751 // ------------------------------------------------------------
01752 
01753 // --- Statistics
01754 
01755 void memoryBlock::stats(ostream & out, bool header,
01756                         long int & global_defs,
01757                         long int & global_merge_defs,
01758                         long int & global_weak_defs,
01759                         long int & global_uses,
01760                         long int & global_merge_uses)
01761 {
01762 
01763   int total_defs;
01764   int merge_defs;
01765   int weak_defs;
01766   int total_uses;
01767   int merge_uses;
01768 
01769   Defs.stats(total_defs, merge_defs, weak_defs);
01770   Uses.stats(total_uses, merge_uses);
01771 
01772   global_defs += total_defs;
01773   global_merge_defs += merge_defs;
01774   global_weak_defs += weak_defs;
01775   global_uses += total_uses;
01776   global_merge_uses += merge_uses;
01777 
01778   if (pointerOptions::Show_memoryblocks) {
01779 
01780     out.width(35);
01781     if (header)
01782       out << "memoryBlock";
01783     else
01784       out << name();
01785 
01786     out.width(6);
01787     if (header)
01788       out << "#defs";
01789     else
01790       out << total_defs;
01791 
01792     out.width(7);
01793     if (header)
01794       out << "#merge";
01795     else
01796       out << merge_defs;
01797 
01798     out.width(6);
01799     if (header)
01800       out << "#weak";
01801     else
01802       out << weak_defs;
01803 
01804     out.width(6);
01805     if (header)
01806       out << "#uses";
01807     else
01808       out << total_uses;
01809 
01810     out.width(7);
01811     if (header)
01812       out << "#merge";
01813     else
01814       out << merge_uses;
01815 
01816     out.width(12);
01817     if (header)
01818       out << "local-to";
01819     else {
01820       if (_local_to)
01821         out << _local_to->decl()->name();
01822       else
01823         out << "(non-local)";
01824     }
01825 
01826     out.width(6);
01827     if (header)
01828       out << "array";
01829     else {
01830       if (_is_array)
01831         out << "true";
01832       else
01833         out << "false";
01834     }
01835 
01836     out.width(6);
01837     if (header)
01838       out << "index";
01839     else {
01840       if (_is_indexed)
01841         out << "true";
01842       else
01843         out << "false";
01844     }
01845 
01846     out.width(6);
01847     if (header)
01848       out << "heap";
01849     else {
01850       if (is_heap_object())
01851         out << "true";
01852       else
01853         out << "false";
01854     }
01855     
01856     out << endl;
01857   }
01858 }
01859 
01860 void memoryBlock::print_def_use(ostream & o) const
01861 {
01862   o << "memoryBlock: " << name();
01863 
01864   if ( ! _components.empty() ) {
01865     o << " {" << endl;
01866     for (component_map_cp p = _components.begin();
01867          p != _components.end();
01868          ++p)
01869       {
01870         o << "  " << FieldNames.field_name((*p).first) << " ";
01871         o << (*p).second->name() << ";" << endl;
01872       }
01873     o << "}" << endl;
01874   }
01875   else {
01876     o << endl;
01877     o << "  Defs: " << endl;
01878     Defs.print(o);
01879     o << "  Uses: " << endl;
01880     Uses.print(o);
01881   }
01882 }
01883 
01884 void memoryBlock::print(ostream & o, Location * path, Output_mode mode) const
01885 {
01886   o << "memoryBlock: " << name();
01887 
01888   if (mode == NAME_ONLY) {
01889     o << endl;
01890     return;
01891   }
01892 
01893   if ( ! _components.empty() ) {
01894     o << " {" << endl;
01895     for (component_map_cp p = _components.begin();
01896          p != _components.end();
01897          ++p)
01898       {
01899         o << "  " << FieldNames.field_name((*p).first) << " ";
01900         (*p).second->print(o, path, mode);
01901       }
01902     o << "}";
01903   }
01904   else {
01905     memoryblock_list ps;
01906     o << endl;
01907 
01908     if (mode == ALL_VALUES) {
01909 
01910       /*
01911       // --- Print out the whole points-to relation
01912 
01913       for (path_pointer_list_cp p = _points_to.begin();
01914            p != _points_to.end();
01915            ++p)
01916         {
01917           o << "     at " << (*p).path() << endl;
01918           for (block_list::const_iterator q = (*p).begin();
01919                q != (*p).end();
01920                ++q)
01921             {
01922               o << "        " << (*q)->name() << endl;
01923             }
01924         }
01925       */
01926     }
01927     else {
01928 
01929       // --- To see the status "after" the current statement (e.g., to
01930       // see the results of an assignment, we set the stmt_num ahead
01931       // one.
01932 
01933       /*
01934 
01935       if (mode == AFTER_ASSIGNMENT) {
01936         Path temp(*path);
01937         temp.next_stmt();
01938         star(&temp, ps);
01939       }
01940       else
01941         star(path, ps);
01942       */
01943 
01944       for (memoryblock_list_p p = ps.begin();
01945            p != ps.end();
01946            ++p)
01947         {
01948           memoryBlock * pb = *p;
01949 
01950           o << "        --> " << pb->name() << endl;
01951         }
01952     }
01953   }
01954 }
01955 
01956 string memoryBlock::name() const
01957 {
01958   // if (_name.empty()) {
01959 
01960   string name0;
01961 
01962   if (container() && ! is_array_element()) {
01963     return container()->name() + "." + decl()->name();
01964   }
01965   else {
01966 
01967     string & name1 = _decl->name();
01968 
01969     if (decl()->type() &&
01970         decl()->type()->is_ellipsis())
01971       name1 = string("...");
01972 
01973     if (_local_to)
01974       return _local_to->decl()->name() + "::" + name1;
01975     else {
01976 
01977       if (_allocation_site) {
01978 
01979         procLocation * alloc_proc = Location::procedure(_allocation_site);
01980 
01981         if (alloc_proc->proc()->decl()->decl_location() == declNode::UNKNOWN)
01982           {
01983             // -- Allocated in a library routine, print the caller
01984 
01985             procLocation * caller = Location::procedure(alloc_proc->stmt_location());
01986             if (caller)
01987               return caller->proc()->decl()->name() + "/" + name1;
01988           }
01989       }
01990 
01991       return name1;
01992     }
01993   }
01994 
01995   // }
01996   // else
01997   //   return _name;
01998 }
01999 
02000 string memoryBlock::generate_su_field_name(const string & field) const
02001 {
02002   //  if (_name.empty()) {
02003 
02004     string & name1 = _decl->name();
02005 
02006     if (decl()->type() &&
02007         decl()->type()->is_ellipsis())
02008       name1 = string("...");
02009 
02010     return name1 + "." + field;
02011     //  }
02012     //  else
02013     //    return _name + "." + field;
02014 }
02015 
02016 // ------------------------------------------------------------
02017 //  Field-name database
02018 // ------------------------------------------------------------
02019 
02020 // Since the number of possible field names is small, we keep them in
02021 // a database and then refer to them by number in the memoryBlock class.
02022 
02023 memoryBlock::FieldNameDB memoryBlock::FieldNames;
02024 
02025 int memoryBlock::FieldNameDB::get_field(const string & name)
02026 {
02027   field_name_map_p p = _fields.find(name);
02028   if (p == _fields.end()) {
02029     ++_count;
02030     _fields[name] = _count;
02031     return _count;
02032   }
02033   else
02034     return (*p).second;
02035 }
02036 
02037 string memoryBlock::FieldNameDB::field_name(int index)
02038 {
02039   field_name_map_p p = _fields.begin();
02040 
02041   while (p != _fields.end()) {
02042     if ((*p).second == index)
02043       return (*p).first;
02044     ++p;
02045   }
02046   return string("");
02047 }
02048 
02049 int memoryBlock::FieldNameDB::ArrayField = -1;

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