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  

constants.cc

Go to the documentation of this file.
00001 // $Id: constants.cc,v 1.29 2003/08/08 15:16:29 toktb Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2003 University of Texas at Austin
00008 // 
00009 //  Samuel Z. Guyer
00010 //  Adam Brown
00011 //  Teck Bok Tok
00012 //  Paul Arthur Navratil
00013 //  Calvin Lin
00014 // 
00015 //  Permission is hereby granted, free of charge, to any person
00016 //  obtaining a copy of this software and associated documentation
00017 //  files (the "Software"), to deal in the Software without
00018 //  restriction, including without limitation the rights to use, copy,
00019 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00020 //  of the Software, and to permit persons to whom the Software is
00021 //  furnished to do so, subject to the following conditions:
00022 //  
00023 //  The above copyright notice and this permission notice shall be
00024 //  included in all copies or substantial portions of the Software.
00025 //  
00026 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00027 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00028 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00029 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00030 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00031 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00032 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00033 //  THE SOFTWARE.
00034 //
00035 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00036 //  Computer Science for inspiring parts of the C-Breeze design.
00037 //
00038 // ----------------------------------------------------------------------
00039 
00040 #include "c_breeze.h"
00041 #include "print_walker.h"
00042 #include "constants.h"
00043 
00044 constantAnalyzer::constantAnalyzer()
00045   : _schar_constants(),
00046     _uchar_constants(),
00047     _sshort_constants(),
00048     _ushort_constants(),
00049     _sint_constants(),
00050     _uint_constants(),
00051     _slong_constants(),
00052     _ulong_constants(),
00053     _float_constants(),
00054     _double_constants(),
00055     _null(0),
00056     _top(new constant()),
00057     _bottom(new constant()),
00058     _non_null(new constant()),
00059     _expr_values()
00060 {}
00061 
00062 void constantAnalyzer::clear()
00063 {
00064   _expr_values.clear();
00065 }
00066 
00067 constantAnalyzer::~constantAnalyzer()
00068 {
00069   /*
00070   if (pointerOptions::Verbose_constants)
00071     cout << "Number of unique constants: " << _constants.size() << endl;
00072   */
00073 
00074   delete _top;
00075   delete _bottom;
00076   delete _non_null;
00077 }
00078 
00083 bool constantAnalyzer::has_truth_value(const constant * val, bool & value)
00084 {
00085   if (val == _non_null) {
00086     value = true;
00087     return true;
00088   }
00089 
00090   if ((val == _top) ||
00091       (val == _bottom))
00092     {
00093       return false;
00094     }
00095 
00096   
00097   value = val->Boolean();
00098   return true;
00099 }
00100 
00101 const constant * constantAnalyzer::lookup(const constant & value)
00102 {
00103   pair< constant_set_p, bool > result;
00104 
00105   bool found_type = false;
00106 
00107   const basic_type & bt = value.basic();
00108 
00109   if (bt == basic_type::SChar) {
00110     result = _schar_constants.insert(value);
00111     found_type = true;
00112   }
00113 
00114   if (bt == basic_type::UChar) {
00115     result = _uchar_constants.insert(value);
00116     found_type = true;
00117   }
00118 
00119   if (bt == basic_type::SShort) {
00120     result = _sshort_constants.insert(value);
00121     found_type = true;
00122   }
00123 
00124   if (bt == basic_type::UShort) {
00125     result = _ushort_constants.insert(value);
00126     found_type = true;
00127   }
00128 
00129   if (bt == basic_type::SInt) {
00130     result = _sint_constants.insert(value);
00131     found_type = true;
00132   }
00133 
00134   if (bt == basic_type::UInt) {
00135     result = _uint_constants.insert(value);
00136     found_type = true;
00137   }
00138 
00139   if (bt == basic_type::SLong) {
00140     result = _slong_constants.insert(value);
00141     found_type = true;
00142   }
00143 
00144   if (bt == basic_type::ULong) {
00145     result = _ulong_constants.insert(value);
00146     found_type = true;
00147   }
00148 
00149   if (bt == basic_type::Float) {
00150     result = _float_constants.insert(value);
00151     found_type = true;
00152   }
00153 
00154   if (bt == basic_type::Double) {
00155     result = _double_constants.insert(value);
00156     found_type = true;
00157   }
00158 
00159   if (found_type) {
00160     constant_set_p p = result.first;
00161     return & (*p);
00162   }
00163   else
00164     return _bottom;
00165 }
00166 
00167 const constant * constantAnalyzer::lookup_flowvalue(memoryDef * def)
00168 {
00169   // -- No def -> bottom
00170 
00171   if (def == 0)
00172     return _bottom;
00173 
00174   // -- No current value -> top
00175 
00176   const constant * result = def->value();
00177 
00178   if ( ! result)
00179     result = _bottom;
00180 
00181   // -- Special case for pointers
00182 
00183   const memoryblock_set & points_to = def->points_to();
00184 
00185   if (points_to.size() > 0)
00186     result = evaluate_points_to(points_to);
00187 
00188   return result;
00189 }  
00190 
00191 bool constantAnalyzer::update_flowvalue(const constant * val, memoryDef * def)
00192 {
00193   bool change = false;
00194 
00195   // -- NOTE: Don't use lookup_flow() because it handles the special
00196   // pointer case, which can cause the constants analysis not to converge.
00197 
00198   // const constant * old = lookup_flowvalue(def);
00199 
00200   const constant * old = def->value();
00201 
00202   if ( ! old)
00203     old = _top;
00204 
00205   // -- No value: use top
00206 
00207   if (! val)
00208     val = _top;
00209 
00210   // -- Handle additive updates
00211 
00212   // All are additive: if (def->is_additive())
00213   const constant * res = meet(val, old);
00214 
00215   if (res != _top) {
00216     def->set_value(res);
00217     change = (old != res);
00218 
00219     if (pointerOptions::Verbose_constants) {
00220       cout << "  + Update value of " << def->owner()->name()
00221            << ": old = " << to_string(old) 
00222            << ", new = " << to_string(val) 
00223            << ", res = " << to_string(res) << endl;
00224     }
00225   }
00226 
00227   return change;
00228 } 
00229 
00230 const constant * constantAnalyzer::meet(const constant * one, const constant * two)
00231 {
00232   // Case 1 : BOTTOM ^ <anything> = BOTTOM
00233 
00234   if ((one == _bottom) ||
00235       (two == _bottom))
00236     return _bottom;
00237 
00238   // Case 2 : TOP ^ <value> = <value>
00239 
00240   if (one == _top)
00241     return two;
00242 
00243   if (two == _top)
00244     return one;
00245 
00246   // Case 4 : NON-NULL ^ NON-NULL = NON-NULL
00247 
00248   if ((one == _non_null) &&
00249       (two == _non_null))
00250     return _non_null;
00251 
00252   // Case 5: NON_NULL ^ (!0) = NON_NULL
00253 
00254   if (one == _non_null) {
00255     if (two->is_zero())
00256       return _bottom;
00257     else
00258       return _non_null;
00259   }
00260 
00261   if (two == _non_null) {
00262     if (one->is_zero())
00263       return _bottom;
00264     else
00265       return _non_null;
00266   }
00267 
00268   // Case 6 : <value1> ^ <value2> = <value1>, if value1 == value2
00269 
00270   if (one == two)
00271     return one;
00272 
00273   return _bottom;
00274 }
00275 
00276 const constant * constantAnalyzer::rebuild_flowvalue(pointerValue & pointer)
00277 {
00278   const constant * result = _top;
00279 
00280   if (pointerOptions::Verbose_constants)
00281     cout << "  + Rebuild constant:" << endl;
00282 
00283   if (pointer.is_address)
00284     result = evaluate_points_to(pointer.blocks);
00285   else
00286     if (pointer.blocks.empty())
00287       result = _bottom;
00288     else {
00289       for (memoryblock_set_p p = pointer.blocks.begin();
00290            p != pointer.blocks.end();
00291            ++p)
00292         {
00293           memoryBlock * block = *p;
00294 
00295           if (block->decl()->decl_location() == declNode::ENUM) {
00296             declNode * ed = block->decl();
00297             exprNode * in = ed->init();
00298             if (! in)
00299               cout << "No init for " << block->name() << " decl = 0x" << ed << endl;
00300             else {
00301               const constant * enum_val = lookup(in->value());
00302 
00303               if (pointerOptions::Verbose_constants)
00304                 cout << "    - Enum " << block->name() << " = " << to_string(enum_val) << endl;
00305 
00306               result = meet(result, enum_val);
00307             }
00308           }
00309           else {
00310 
00311             memoryUse * use = block->current_use();
00312             if (use) {
00313 
00314               // -- Get the value associated with the reaching def
00315             
00316               const constant * val = 0;
00317 
00318               memoryDef * def = use->reaching_def();
00319               if (def)
00320                 val = lookup_flowvalue(def);
00321               else
00322                 val = bottom();
00323 
00324               // -- Accumulate this value into the result
00325 
00326               result = meet(result, val);
00327 
00328               if (pointerOptions::Verbose_constants) {
00329                 cout << "    - Value of " << block->name() << " = " << to_string(val) << endl;
00330                 cout << "      + use at " << * (use->where());
00331 
00332                 if (def)
00333                   cout << " def at " << * (def->where()) << endl;
00334                 else
00335                   cout << " (no def)" << endl;
00336               }
00337             }
00338           }
00339         }
00340     }
00341   
00342   if (pointerOptions::Verbose_constants)
00343     cout << "  => " << to_string(result) << endl;
00344 
00345   return result;
00346 }
00347 
00348 void constantAnalyzer::record_expression(exprNode * expr, const constant * val)
00349 {
00350   if (val && (val != _top)) {
00351     expr_value_map_p p = _expr_values.find(expr);
00352     if (p == _expr_values.end())
00353       _expr_values[expr] = val;
00354     else
00355       _expr_values[expr] = meet((*p).second, val);
00356 
00357     if (pointerOptions::Verbose_constants) {
00358 
00359       const constant * newval = _expr_values[expr];
00360 
00361       cout << "  + Record constant expression = " << to_string(val) << endl;
00362       cout << "      - Accumulated value = " << to_string(newval) << endl;
00363     }
00364   }
00365 }
00366 
00367 void constantAnalyzer::record_stmt(stmtNode * stmt, const constant * val)
00368 {
00369   if (val && (val != _top)) {
00370     stmt_value_map_p p = _stmt_values.find(stmt);
00371     if (p == _stmt_values.end())
00372       _stmt_values[stmt] = val;
00373     else
00374       _stmt_values[stmt] = meet((*p).second, val);
00375 
00376     if (pointerOptions::Verbose_constants) {
00377 
00378       const constant * newval = _stmt_values[stmt];
00379 
00380       cout << "  + Record constant expression = " << to_string(val) << endl;
00381       cout << "      - Accumulated value = " << to_string(newval) << endl;
00382     }
00383   }
00384 }
00385 
00395 const constant * constantAnalyzer::evaluate_points_to(const memoryblock_set & points_to)
00396 {
00397   // -- Check for special cases
00398 
00399   bool points_to_null = false;
00400   bool points_to_heap = false;
00401     
00402   for (memoryblock_set_cp p = points_to.begin();
00403        p != points_to.end();
00404        ++p)
00405     {
00406       memoryBlock * target = *p;
00407 
00408       if (target == _null)
00409         points_to_null = true;
00410 
00411       if (target->is_heap_object())
00412         points_to_heap = true;
00413     }
00414 
00415   if (points_to_null && 
00416       (points_to.size() == 1)) {
00417 
00418     // -- Null pointer; return zero
00419 
00420     return lookup(constant(0));
00421   }
00422 
00423   if (points_to_heap) {
00424 
00425     // -- Heap allocation can fail, so we return bottom
00426 
00427     return _bottom;
00428   }
00429 
00430   // -- Regular pointer: always non-null
00431 
00432   return _non_null;
00433 }
00434 
00435 
00436 const constant * constantAnalyzer::lookup_expression(exprNode * expr)
00437 {
00438   expr_value_map_p p = _expr_values.find(expr);
00439 
00440   const constant * result = 0;
00441 
00442   if (p == _expr_values.end())
00443     result = _bottom;
00444   else
00445     result = (*p).second;
00446 
00447   if (pointerOptions::Verbose_constants) {
00448     if (p != _expr_values.end())
00449       cout << "  + Lookup constant expression = " << to_string(result) << endl;
00450   }
00451 
00452   return result;
00453 }
00454 
00455 const constant * constantAnalyzer::lookup_stmt(stmtNode * stmt)
00456 {
00457   stmt_value_map_p p = _stmt_values.find(stmt);
00458 
00459   const constant * result = 0;
00460 
00461   if (p == _stmt_values.end())
00462     result = _bottom;
00463   else
00464     result = (*p).second;
00465 
00466   if (pointerOptions::Verbose_constants) {
00467     if (p != _stmt_values.end())
00468       cout << "  + Lookup constant statement = " << to_string(result) << endl;
00469   }
00470 
00471   return result;
00472 }
00473 
00474 // -- Non-pointer expressions
00475 
00476 void constantAnalyzer::at_id(stmtLocation * current, idNode * id,
00477                              pointerValue & block)
00478 {
00479   const constant * val = rebuild_flowvalue(block);
00480   block.constant_value = val;
00481 
00482   if (block.is_a_use)
00483     record_expression(id, val);
00484 }
00485 
00486 void constantAnalyzer::at_sizeof(stmtLocation * current,
00487                                  threeAddrNode *t,
00488                                  pointerValue & operand,
00489                                  pointerValue & result)
00490 {
00491   const constant * result_c = _bottom;
00492 
00493   typeNode *type = t->sizeof_type();
00494   if(!type && t->rhs1()) type = t->rhs1()->type();
00495 
00496   if (type && (type->typ() == Prim)) {
00497     primNode * prim = (primNode *) type;
00498     basic_type & basic = prim->basic();
00499     constant size(basic.size());
00500     result_c = lookup(size);
00501   }
00502   record_stmt(t, result_c);
00503 }
00504 
00505 void constantAnalyzer::at_unary(stmtLocation * current,
00506                                 stmtNode *s,
00507                                 pointerValue & operand,
00508                                 pointerValue & result)
00509 {
00510   assert(s->typ() == Condition || s->typ() == ThreeAddr);
00511   Operator *op = s->typ()==Condition ? ((conditiongotoNode*)s)->op() :
00512                                        ((threeAddrNode*)s)->op();
00513   assert(op && op->is_unary());
00514   assert (op->id() != Operator::SIZEOF);
00515 
00516   const constant * result_c = _bottom;
00517   const constant * operand_c = operand.constant_value;
00518 
00519   if (operand_c == _non_null) {
00520 
00521     // -- Non-null cases
00522 
00523     if (op->id() == '!') {
00524 
00525       // -- !p is false for non-null pointers
00526 
00527       result_c = lookup(constant(0));
00528     }
00529     else {
00530 
00531       // -- Any other operator goes to bottom
00532 
00533       result_c = _bottom;
00534     }
00535   }
00536   else {
00537 
00538     // -- Check for top and bottom
00539 
00540     if ((operand_c == _bottom) ||
00541         (operand_c == _top))
00542       result_c = operand_c;
00543     else {
00544 
00545       // -- Compute
00546 
00547       constant unary_result = constant::eval(op, * operand_c);
00548       result_c = lookup(unary_result);
00549     }
00550   }
00551 
00552   result.constant_value = result_c;
00553 
00554   if (result.is_a_use)
00555     if(s) record_stmt(s, result_c);
00556 }
00557 
00558 void constantAnalyzer::at_binary(stmtLocation * current,
00559                                  stmtNode *s,
00560                                  pointerValue & left,
00561                                  pointerValue & right,
00562                                  pointerValue & result)
00563 {
00564   const constant * result_c = _bottom;    
00565   const constant * left_c = left.constant_value;
00566   const constant * right_c = right.constant_value;
00567 
00568   assert(s->typ() == Condition || s->typ() == ThreeAddr);
00569   Operator *op = s->typ()==Condition ? ((conditiongotoNode*)s)->op() :
00570                                        ((threeAddrNode*)s)->op();
00571   assert(op && ! op->is_unary());
00572 
00573   if ((left_c == _non_null) ||
00574       (right_c == _non_null))
00575     {
00576       // -- Non-null cases
00577 
00578       switch (op->id()) {
00579 
00580       case '+':
00581       case '-':
00582 
00583         // -- Pointer arithmetic is a no-op
00584 
00585         result_c = _non_null;
00586         break;
00587 
00588       case Operator::EQ:
00589 
00590         // -- Compare: non_null == <value>. Two cases: (1) non_null == 0 is
00591         // false, (2) non_null == <other> is bottom.
00592 
00593         if (left_c->is_zero() ||
00594             right_c->is_zero())
00595           result_c = lookup(constant(0));
00596         else
00597           result_c = _bottom;
00598         break;
00599 
00600       case Operator::NE:
00601 
00602         // -- Compare: non_null != <value>. Two cases: (1) non_null != 0 is
00603         // true, (2) non_null == <other> is bottom.
00604 
00605         if (left_c->is_zero() ||
00606             right_c->is_zero())
00607           result_c = lookup(constant(1));
00608         else
00609           result_c = _bottom;
00610         break;
00611 
00612       default:
00613         result_c = _bottom;
00614       }
00615     }
00616   else
00617     {
00618       // -- Check for top and bottom
00619 
00620       if ((left_c != _bottom) &&
00621           (left_c != _top) &&
00622           (right_c != _bottom) &&
00623           (right_c != _top))
00624         {
00625           if ((op->id() == '/') &&
00626               right_c->is_zero())
00627             {
00628               /*
00629               cout << "WARNING: Division by zero at " << * current << endl;
00630               output_context oc(cout);
00631               current->stmt()->output(oc, 0);
00632               cout << endl;
00633               */
00634             }
00635           else {
00636 
00637             // -- Go ahead and evaluate
00638 
00639             constant binary_result = constant::eval(op, *left_c, *right_c);
00640             result_c = lookup(binary_result);
00641           }
00642         }
00643     }
00644   
00645   result.constant_value = result_c;
00646 
00647   if (result.is_a_use)
00648     if(s) record_stmt(s, result_c);
00649 }
00650 
00651 
00652 void constantAnalyzer::at_const(stmtLocation * current, constNode * cons,
00653                                 pointerValue & result)
00654 {
00655   // -- Skip strings
00656 
00657   if (cons->value().is_str()) {
00658     if (pointerOptions::Verbose_constants)
00659       cout << "String constant; skipping" << endl;
00660     result.constant_value = _bottom;
00661   }
00662   else {
00663     typeNode * type = cons->type();
00664     if (type->typ() == Prim) {
00665 
00666       primNode * prim = (primNode *) type;
00667       result.constant_value = lookup(constant::cast(prim->basic(), cons->value()));
00668     }
00669     else
00670       result.constant_value = lookup(cons->value());
00671   }
00672 }
00673 
00674   // -- Pointer expressions
00675 
00676 void constantAnalyzer::at_address(stmtLocation * current,
00677                                   operandNode * operand,
00678                                   pointerValue & result) {
00679   if(operand->addr())
00680     result.constant_value = _bottom; // Not working: _non_null;
00681 }
00682 
00683 void constantAnalyzer::at_cast(stmtLocation * current,
00684                                operandNode * operand,
00685                                pointerValue & operand_val,
00686                                pointerValue & result) {
00687   if(! operand->cast()) return;
00688 
00689   const constant * result_c = _bottom;
00690   const constant * operand_c = operand_val.constant_value;
00691 
00692 
00693   if (operand_c) {
00694 
00695     // -- Non-null value just propagates
00696 
00697     if (operand_c == _non_null)
00698       {
00699         result_c = _non_null;
00700       }
00701     else {
00702 
00703       // -- Check for top and bottom
00704 
00705       if ((operand_c == _bottom) ||
00706           (operand_c == _top))
00707         result_c = operand_c;
00708       else {
00709 
00710         // -- Compute
00711 
00712         typeNode * type = operand->cast();
00713 
00714         if (type->typ() == Prim) {
00715           primNode * prim = (primNode *) type;
00716           constant cast_result = constant::cast(prim->basic(), * operand_c);
00717           result_c = lookup(cast_result);
00718         }
00719         else
00720           result_c = operand_c;
00721       }
00722     }
00723   }
00724 
00725   result.constant_value = result_c;
00726 
00727   if (result.is_a_use)
00728     record_expression(operand, result_c);
00729 } // at_cast
00730 
00731 
00732 void constantAnalyzer::at_dereference(stmtLocation * current,
00733                                       operandNode * operand,
00734                                       pointerValue & result) {
00735   if(operand->star()) {
00736     const constant * val = rebuild_flowvalue(result);
00737     result.constant_value = val;
00738 
00739     if (result.is_a_use)
00740       record_expression(operand, val);
00741   }
00742 } // at_dereference
00743 
00744 
00745 void constantAnalyzer::at_field_access(stmtLocation * current,
00746                                        operandNode * operand,
00747                                        pointerValue & result) {
00748   if(! operand->fields().empty()) {
00749     const constant * val = rebuild_flowvalue(result);
00750     result.constant_value = val;
00751 
00752     if (result.is_a_use)
00753       record_expression(operand, val);
00754   }
00755 } // at_field_access
00756 
00757 
00758 void constantAnalyzer::at_index(stmtLocation * current,
00759                                 operandNode * operand,
00760                                 pointerValue & result) {
00761   if(operand->index()) {
00762     const constant * val = rebuild_flowvalue(result);
00763     result.constant_value = val;
00764 
00765     if (result.is_a_use)
00766       record_expression(operand, val);
00767   }
00768 } // at_index
00769 
00770 // -- Assignments
00771 
00772 void constantAnalyzer::at_assignment(stmtLocation * current,
00773                                      pointerValue & left,
00774                                      pointerValue & right,
00775                                      pointerValue & result,
00776                                      memoryblock_set & changes)
00777 {
00778   const constant * right_c = right.constant_value;
00779 
00780   if (! right_c)
00781     right_c = _bottom;
00782 
00783   result.constant_value = right_c;
00784 
00785   for (memoryblock_set_p p = left.blocks.begin();
00786        p != left.blocks.end();
00787        ++p)
00788     {
00789       memoryBlock * block = *p;
00790 
00791       // -- Skip write-proctected blocks
00792 
00793       if ( ! block->write_protected()) {
00794 
00795         memoryDef * def = block->current_def();
00796 
00797         const constant * newval = _top;
00798 
00799         if (def->is_weak()) {
00800           // memoryDef * previous_def = def->previous();
00801           memoryUse * weak_use = block->current_use();
00802           memoryDef * previous_def = weak_use->reaching_def();
00803 
00804           if (previous_def)
00805             newval = meet(right_c, lookup_flowvalue(previous_def));
00806           else
00807             newval = right_c;
00808         }
00809         else {
00810           newval = right_c;
00811         }
00812 
00813         bool change = update_flowvalue(newval, def);
00814       
00815         if (change)
00816           changes.insert(block);
00817       }
00818     }
00819 }
00820 
00821 void constantAnalyzer::at_self_assignment(Location * source,
00822                                           Location * target,
00823                                           memoryBlock * block,
00824                                           memoryblock_set & changes)
00825 {
00826 
00827   if ( ! block->write_protected()) {
00828 
00829     // -- Build the current value using the current use (which should be at
00830     // the source location).
00831 
00832     pointerValue temp(block);
00833     const constant * cur_val = rebuild_flowvalue(temp);
00834 
00835     // -- Assign it to the current def (which should be at the target
00836     // location).
00837 
00838     memoryDef * def = block->current_def();
00839 
00840     const constant * newval = _top;
00841 
00842     if (def->is_weak()) {
00843       // memoryDef * previous_def = def->previous();
00844 
00845       memoryUse * weak_use = block->current_use();
00846       memoryDef * previous_def =weak_use->reaching_def();
00847 
00848       if (previous_def)
00849         newval = meet(cur_val, lookup_flowvalue(previous_def));
00850       else
00851         newval = cur_val;
00852     }
00853     else {
00854       newval = cur_val;
00855     }
00856 
00857     bool change = update_flowvalue(newval, def);
00858       
00859     if (change) {
00860       changes.insert(block);
00861     }
00862   }
00863 }
00864 
00865 
00866 void constantAnalyzer::at_parameter_pass(Location * current,
00867                                          pointerValue & left,
00868                                          pointerValue & right,
00869                                          memoryblock_set & changes)
00870 {
00871   if (right.is_address)
00872     return;
00873 
00874   const constant * right_c = right.constant_value;
00875 
00876   if (! right_c)
00877     right_c = _top;
00878 
00879   for (memoryblock_set_p p = left.blocks.begin();
00880        p != left.blocks.end();
00881        ++p)
00882     {
00883       memoryBlock * block = *p;
00884       memoryDef * def = block->current_def();
00885 
00886       if (def) {
00887 
00888         bool change = update_flowvalue(right_c, def);
00889       
00890         if (change) {
00891           changes.insert(block);
00892         }
00893       }
00894       else {
00895         // cout << "ERROR: no current def for " << block->name()
00896         //     << " at " << * current << endl;
00897       }
00898     }
00899 }
00900 
00901   // -- Statement types
00902 
00903 void constantAnalyzer::at_return(stmtLocation * stmt,
00904                                  returnNode * ret,
00905                                  pointerValue & result,
00906                                  pointerValue & return_val)
00907 {
00908   return_val.constant_value = result.constant_value;
00909 }
00910 
00911   // -- Process a merge point
00912 
00913 void constantAnalyzer::at_merge(Location * where,
00914                                 memoryBlock * block,
00915                                 memoryuse_list & phi_uses,
00916                                 pointerValue & result,
00917                                 memoryblock_set & changes)
00918 {
00919   memoryDef * def = block->current_def();
00920 
00921   const constant * merged_val = _top;
00922 
00923   for (memoryuse_list_p p = phi_uses.begin();
00924        p != phi_uses.end();
00925        ++p)
00926     {
00927       memoryUse * phi_use = *p;
00928       memoryDef * reaching_def = phi_use->reaching_def();
00929 
00930       if (reaching_def)
00931         merged_val = meet(merged_val, lookup_flowvalue(reaching_def));
00932     }
00933 
00934   bool change = update_flowvalue(merged_val, def);
00935 
00936   if (change) {
00937     changes.insert(block);
00938   }
00939 }
00940 
00941   // -- Control-flow options
00942 
00943 void constantAnalyzer::at_basicblock_entry(basicblockLocation * block,
00944                                            procedureInfo * info,
00945                                            pointerValue & initial)
00946 {
00947   initial.constant_value = _top;
00948 }
00949 
00950 void constantAnalyzer::at_stmt_entry(stmtLocation * stmt,
00951                                      pointerValue & result)
00952 {
00953   result.constant_value = _top;
00954 }
00955 
00956   // -- Procedure boundaries
00957 
00958 void constantAnalyzer::at_conservative_procedure_call(stmtLocation * current,
00959                                                       operandNode * call,
00960                                                       operand_list & args,
00961                                                       pointerValue & call_target,
00962                                                       pointervalue_list & arguments,
00963                                                       memoryblock_set & reachable_blocks,
00964                                                       pointerValue & return_val,
00965                                                       memoryblock_set & changes)
00966 {
00967   // -- At a procedure call with no source, all reachable blocks become
00968   // BOTTOM.
00969 
00970   for (memoryblock_set_p p = reachable_blocks.begin();
00971        p != reachable_blocks.end();
00972        ++p)
00973     {
00974       memoryBlock * block = *p;
00975 
00976       if ( ! block->write_protected()) {
00977 
00978         memoryDef * def = block->current_def();
00979 
00980         bool change = update_flowvalue(bottom(), def);
00981       
00982         if (change) {
00983           changes.insert(block);
00984         }
00985       }
00986     }
00987 }
00988 
00989 // ----------------------------------------------------------------------
00990 //  Changer
00991 // ----------------------------------------------------------------------
00992 
00993 constantsChanger::constantsChanger(constantAnalyzer * constants,
00994                                    bool simplify)
00995   : Changer( Postorder, Subtree, true),
00996     _constants(constants),
00997     _simplify(simplify)
00998 {}
00999 
01000 Node * constantsChanger::at_id(idNode * id, Order ord)
01001 {
01002   // -- Look up the constant value of this expression
01003 
01004   const constant * val = _constants->lookup_expression(id);
01005 
01006   // -- See if it has a recorded value
01007 
01008   if (_constants->has_value(val))
01009     {
01010       // -- It does, so return that value
01011 
01012       if (pointerOptions::Verbose_constants) {
01013         cout << "--- Replace constant -----------------------------------" << endl;
01014         output_context oc(cout);
01015         id->output(oc,0);
01016         cout << endl;
01017         cout << val->to_string() << endl;
01018       }
01019 
01020       return new constNode( *val );
01021     }
01022   else {
01023 
01024     // -- There's no recorded value, but it still could be a combination of
01025     // arithmetic operators and constants, e.g. "5+(4/2)". Evaluate the
01026     // expression and check again for a constant value.
01027 
01028     id->eval();
01029     if ( ! id->value().no_val()) {
01030       constNode * out = new constNode(id->value());
01031       return out;
01032     }
01033   }
01034   
01035   return id;
01036 }
01037 
01038 
01039 Node * constantsChanger::at_threeAddr(threeAddrNode * t, Order ord)
01040 {
01041   // -- Look up the constant value of this expression
01042 
01043   const constant * val = _constants->lookup_stmt(t);
01044 
01045   // -- See if it has a recorded value
01046 
01047   if (_constants->has_value(val))
01048     {
01049       // -- It does, so return that value
01050 
01051       if (pointerOptions::Verbose_constants) {
01052         cout << "--- Replace constant -----------------------------------" << endl;
01053         output_context oc(cout);
01054         if(t->rhs1()) {
01055           if(! t->rhs2() && t->op()) { // unary
01056             oc << t->op()->print();  oc.space();
01057           }
01058           t->rhs1()->output(oc,0);
01059           if(t->rhs2()) {
01060             oc.space();  oc << t->op()->print();  oc.space();
01061             t->rhs2()->output(oc,0);
01062           }
01063         }
01064         cout << endl;
01065         cout << val->to_string() << endl;
01066       }
01067 
01068       operandNode *rhs = t->rhs1();
01069       rhs->var( new constNode( *val ) );
01070       rhs->star(false);  rhs->addr(false);  rhs->fields().clear();
01071       rhs->index(NULL);
01072       t->rhs2(NULL);  t->op(NULL);  t->sizeof_type(NULL);
01073     }
01074   else {
01075 
01076     // -- There's no recorded value, but it still could be a combination of
01077     // arithmetic operators and constants, e.g. "5+(4/2)". Evaluate the
01078     // expression and check again for a constant value.
01079 
01080     exprNode *expr = NULL;
01081     if(t->rhs1()) {
01082       if(! t->rhs2()) {
01083         if(t->op()) // unary
01084           expr = new unaryNode(t->op()->id(), t->rhs1());
01085         else
01086           expr = t->rhs1();
01087       } else if(t->rhs2())
01088         expr = new binaryNode(t->op()->id(), t->rhs1(), t->rhs2());
01089     }
01090 
01091     if(expr) {
01092       expr->eval();
01093       if ( ! expr->value().no_val()) {
01094         operandNode *rhs = t->rhs1();
01095         rhs->var( new constNode( *val ) );
01096         rhs->star(false);  rhs->addr(false);  rhs->fields().clear();
01097         rhs->index(NULL);
01098         t->rhs2(NULL);  t->op(NULL);  t->sizeof_type(NULL);
01099       }
01100       if(expr != t->rhs1()) delete expr;
01101     }
01102   }
01103   
01104   return t;
01105 }
01106 
01107 
01108 Node * constantsChanger::at_conditiongoto(conditiongotoNode * C, Order ord)
01109 {
01110   // -- Only simplify if indicated
01111 
01112   if ( ! _simplify)
01113     return C;
01114 
01115   // -- Get the value of the condition
01116 
01117   const constant * val = _constants->lookup_stmt(C);
01118 
01119   bool is_constant = false;
01120   bool which_branch;
01121 
01122   // -- If the variable is not TOP or BOTTOM, then we have a constant.
01123 
01124   if (_constants->has_truth_value(val, which_branch))
01125     {
01126       // The branch argument above gets the value
01127 
01128       is_constant = true;
01129     }
01130   else {
01131 
01132     // -- No record for this expression, but it could be a combination of
01133     // arithmetic and constants, e.g., "5+(4/2)". Evaluate it:
01134 
01135     exprNode * expr = NULL;
01136     if(C->left()) {
01137       if(! C->right()) {
01138         if(C->op()) // unary
01139           expr = new unaryNode(C->op()->id(), C->left());
01140         else
01141           expr = C->left();
01142       } else if(C->right())
01143         expr = new binaryNode(C->op()->id(), C->left(), C->right());
01144     }
01145 
01146     if(expr) {
01147       expr->eval();
01148       if ( ! expr->value().no_val()) {
01149         is_constant = true;
01150         which_branch = expr->value().Boolean();
01151       }
01152       if(expr != C->left()) delete expr;
01153     }
01154   }
01155 
01156   // -- If we can determine the outcome, replace the condition with the
01157   // appropriate branch.
01158 
01159   if (is_constant) {
01160     if (! which_branch)
01161       return new exprstmtNode(0);
01162     // replace with a simple goto.
01163     return new gotoNode(C->label(), C->coord());
01164   } else
01165     return C;
01166 }

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