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  

constprop.cc

Go to the documentation of this file.
00001 // $Id: constprop.cc,v 1.6 2003/08/11 14:27:32 toktb Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2000 University of Texas at Austin
00008 // 
00009 //  Teck Bok Tok
00010 //  Samuel Z. Guyer
00011 //  Daniel A. Jimenez
00012 //  Calvin Lin
00013 // 
00014 //  Permission is hereby granted, free of charge, to any person
00015 //  obtaining a copy of this software and associated documentation
00016 //  files (the "Software"), to deal in the Software without
00017 //  restriction, including without limitation the rights to use, copy,
00018 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00019 //  of the Software, and to permit persons to whom the Software is
00020 //  furnished to do so, subject to the following conditions:
00021 //  
00022 //  The above copyright notice and this permission notice shall be
00023 //  included in all copies or substantial portions of the Software.
00024 //  
00025 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00026 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00027 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00028 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00029 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00030 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00031 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00032 //  THE SOFTWARE.
00033 //
00034 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00035 //  Computer Science for inspiring parts of the C-Breeze design.
00036 //
00037 // ----------------------------------------------------------------------
00038 //
00039 // global constant propagation using reaching definitions info
00040 //
00041 
00042 #include "c_breeze.h"
00043 // #include "semcheck.h"
00044 #include "bits.h"
00045 #include "reaching.h"
00046 #include "constprop.h"
00047 #include "dismantle.h"
00048 
00051 exprNode *constantPropChanger::at_expr (exprNode *e) {
00052   // if e is an idNode, if it can be replaced by a constNode;
00053   // if e is an operandNode that contains an idNode, check that idNode;
00054   // if e has an id index, check that index too.
00055   // else return e untouched.
00056 
00057   if(!e) return NULL;
00058   idNode *id;
00059   if(e->typ() == Operand) {
00060     operandNode *o = (operandNode*) e;
00061     if(o->addr()) return e; // cannot change.
00062     if(o->index()) { // check on the index.
00063       indexNode *index = (indexNode*) at_expr(o->index());
00064       if(index != o->index()) o->index(index); // changed.
00065       // look for case A[i] where A points to a constant string.
00066       indexNode *A = (indexNode*) at_expr(o->var());
00067       if(A != o->var()) {
00068         assert(A->typ() == Const && ((constNode*)A)->value().is_str());
00069         o->var(A);
00070       }
00071       return e; // cannot change e further
00072     }
00073     if(! o->fields().empty()) return e;
00074     if(o->var()->typ() != Id) return e;
00075     id = (idNode*) o->var();
00076   } else if(e->typ() == Id)
00077     id = (idNode*) e;
00078   else return e;
00079 
00080   NodeType typ = e->typ();
00081   constant value;
00082 
00083   // get the ud chain for this node
00084 
00085   threeAddr_list defs = _udchain->defs(e);
00086 
00087   // no definitions?  it could happen.
00088 
00089   if (defs.size() == 0) return e;
00090 
00091   // do all definitions reaching this use define it as the same constant?
00092 
00093   for (threeAddr_list::iterator d=defs.begin(); d!=defs.end(); d++) {
00094 
00095     threeAddrNode *s = *d;
00096 
00097     if (!s) return e; // if it's NULL, it is an ambiguous definition.
00098 
00099     assert (s->lhs());
00100 
00101     // verify the lhs of assignment is same as id.
00102     operandNode *lhs = s->lhs();
00103     if(lhs->star() || lhs->index() || ! lhs->fields().empty()) return e;
00104     if(lhs->var()->typ() != Id) return e;
00105     idNode *lhs_id = (idNode *) lhs->var();
00106     if (lhs_id->decl() != id->decl()) return e;
00107 
00108     if(!s->rhs1() || s->rhs2()) return e; // exactly one rhs?
00109     // note: values of "sizeof(..)" are platform dependent and hence not
00110     // handled here.
00111     operandNode *rhs = s->rhs1();
00112     if(rhs->addr() || rhs->star() || !rhs->fields().empty() ||
00113        rhs->index()) return e;
00114     constant rhs_value; // get the rhs value
00115     if(rhs->var()->typ() == Const) rhs_value = rhs->var()->value();
00116     else return e;
00117 
00118     if(rhs->cast()) { // need to make sure right value after cast
00119       if(rhs_value.is_zero() && rhs->cast()->typ() == Ptr) ; // okay
00120       else {
00121         assert(rhs->cast()->typ() == Prim);
00122         rhs_value= constant::cast(((primNode*)rhs->cast())->basic(), rhs_value);
00123       }
00124     }
00125 
00126     // any unary operator?
00127     if(s->op()) {
00128       int opid = s->op()->id();
00129       if(opid == Operator::UPLUS) ; // okay;
00130       else if(opid == Operator::UMINUS)
00131         rhs_value = constant::eval(s->op(), rhs_value);
00132       else return e; // future work?
00133     }
00134 
00135     if ( d==defs.begin() ) { // first value?
00136       value = rhs_value; // remember it.
00137     } else if (! value.is_equal_to (rhs_value)) // not same constant.
00138       return e;
00139   }
00140   // at this point, every definition of i is the
00141   // same constant value; we'll return a constNode
00142   // with that value.
00143   _changed = true;
00144   if(typ == Id) return new constNode (value); // e is an idNode
00145   return new operandNode(new constNode(value)); // e is an operandNode
00146 } // at_expr
00147 
00148 
00150 Node *constantPropChanger::at_threeAddr (threeAddrNode *t, Order) {
00151   if(t->rhs1()) { // check and replace rhs1
00152     operandNode *v = (operandNode*) at_expr(t->rhs1());
00153     if(v != t->rhs1()) {
00154       v->cast( t->rhs1()->cast() ); // keep the same cast
00155       t->rhs1(v);
00156     }
00157   }
00158   if(t->rhs2()) { // check and replace rhs2
00159     operandNode *v = (operandNode*) at_expr(t->rhs2());
00160     if(v != t->rhs2()) {
00161       v->cast( t->rhs2()->cast() );
00162       t->rhs2(v);
00163     }
00164   }
00165   if(t->lhs() && t->lhs()->index()) { // check and replace lhs's index
00166     indexNode *v = (indexNode*) at_expr(t->lhs()->index());
00167     if(v != t->lhs()->index()) t->lhs()->index(v);
00168   }
00169   // check and replace all call arguments
00170   for(operand_list_p o=t->arg_list().begin(); o!=t->arg_list().end(); o++) {
00171     operandNode *v = (operandNode*) at_expr(*o);
00172     if(v != *o) {
00173       v->cast( (*o)->cast() );
00174       *o = v;
00175     }
00176   }
00177   return t;
00178 } // at_threeAddr
00179 
00180 
00182 Node *constantPropChanger::at_conditiongoto (conditiongotoNode *c, Order) {
00183   assert(c->left());
00184   exprNode *v = at_expr(c->left());
00185   if(v != c->left()) {
00186     assert(v->typ()==Id || v->typ()==Const);
00187     c->left((indexNode*) v);
00188   }
00189 
00190   assert(c->right());
00191   v = at_expr(c->right());
00192   if(v != c->right()) {
00193     assert(v->typ()==Id || v->typ()==Const);
00194     c->right((indexNode*) v);
00195   }
00196   return c;
00197 } // at_conditiongoto
00198 
00200 Node *constantPropChanger::at_return (returnNode *r, Order) {
00201   // Note: procNode's return_decl() is not updated.
00202   // The optimization here will interfere with the backend, in different
00203   // ways depending on if the return_decl() is updated or not.
00204   exprNode *v = at_expr(r->expr());
00205   if(v != r->expr()) r->expr(v);
00206   return r;
00207 } // at_return
00208 
00210 
00212 Node * constantFoldingChanger::at_threeAddr (threeAddrNode *t, Order ord) {
00213   if(!t->rhs1() || !t->op()) return t;
00214 
00215   constNode *c1 = NULL, *c2 = NULL;
00216 
00217   operandNode *o = t->rhs1();
00218   if(o->var()->typ() == Const && !o->star() && !o->addr() &&
00219      o->fields().empty() && !o->index())
00220     c1 = (constNode*) o->var();
00221 
00222   o = t->rhs2();
00223   if(o && o->var()->typ() == Const && !o->star() && !o->addr() &&
00224      o->fields().empty() && !o->index())
00225     c2 = (constNode*) o->var();
00226 
00227   if(c1 && !t->rhs2()) { // unary operator on constant. handle just three cases:
00228     switch(t->op()->id()) {
00229       case Operator::UMINUS:
00230       case '!':
00231         // note: '~' operator is platform dependent.
00232         t->rhs1()->var(new constNode(constant::eval(t->op(), c1->value())));
00233         // fall through
00234       case Operator::UPLUS: t->op(NULL);
00235     }
00236     return t;
00237   }
00238 
00239   // binary operator.
00240 
00241   if(!c1 && !c2) return t; // can't do folding.
00242 
00243   // check for acceptable operator.
00244   switch (t->op()->id()) {
00245     case '*': case '/': case '%': case '+': case '-':
00246     case Operator::LS: case Operator::RS: case Operator::LE: case Operator::GE:
00247     case '<': case '>': case Operator::EQ: case Operator::NE: 
00248     // exclude bit operations - they're not portable
00249     //case '&': case '|': case '^': 
00250       break;
00251     default: 
00252       return t;
00253   }
00254 
00255   // TB new: on top of previous implementation, introduce new optimizations:
00256   // 1. if operator is '+','-' and one operand is zero;
00257   // 2. if operator is '*','/' and one operand is one.
00258   // In these two cases, even if we cannot fold, we may reduce it to just
00259   // operand.
00260 
00261   // what to do with this?
00262   // semcheck_expr_visitor::check(b);
00263 
00264   if(c1 && c2) { // both are constants, do normal folding
00265 
00266     constant oper1 = c1->value();
00267     constant oper2 = c2->value();
00268 
00269 #define cast_constant(cast_type, oper) \
00270   if(cast_type) { \
00271     assert(cast_type->typ() == Prim); \
00272     oper = constant::cast(((primNode*)cast_type)->basic(), oper); \
00273   }
00274     cast_constant(t->rhs1()->cast(), oper1)
00275     cast_constant(t->rhs2()->cast(), oper2)
00276 
00277     if (oper1.basic() == oper2.basic()) {
00278       constant c = constant::eval (t->op(), oper1, oper2);
00279       if (c.no_val() == false) {
00280         _changed = true;
00281         t->rhs1()->var( new constNode (c) );
00282         if(t->rhs1()->cast() && 
00283            !(((primNode*)t->rhs1()->cast())->basic() == oper1.basic()))
00284           t->rhs1()->cast( new primNode(typeNode::NONE, oper1.basic()));
00285         // delete t->rhs2();
00286         t->rhs2( NULL );
00287         t->op(NULL);
00288       }
00289     }
00290 
00291   } else if(t->op()->id()=='+' || t->op()->id()=='-') {
00292     constNode *c = c1 ? c1 : c2; // exactly one of them is a constNode
00293     if(c->value().is_zero()) {
00294       if(c==c1)
00295         t->rhs1(t->rhs2());
00296       t->rhs2(NULL);
00297       if(t->op()->id()=='-' && c==c1) // expression is "0-x"
00298         t->op( Operators::table[Operator::UMINUS] ); // negate
00299       else t->op( NULL );
00300     }
00301 
00302   } else if(t->op()->id()=='*' || t->op()->id()=='/') {
00303     constNode *c = c1 ? c1 : c2; // exactly one of them is constNode
00304     constant v = c->value();
00305 
00306     // there are obviously many cases we can handle
00307     // (1,0,-1,float,double,integer,...), and there is the issue of
00308     // numeric type promotion. Just handle some simple cases below.
00309 
00310     /* if(v.is_zero()) {
00311       if(t->op()->id()=='/') ; // can't fold
00312       else {
00313         t->rhs1()->var(c);
00314         t->rhs2(NULL);
00315         t->op(NULL);
00316       }
00317 
00318     } else*/ if(v.Integer() == 1 /*|| 
00319        v.basic()==basic_type::Float && v.Float()==1.0 ||
00320        v.basic()==basic_type::Double && v.Double()==1.0*/) {
00321       if(t->op()->id()=='/' && c==c1) ; // can't fold
00322       else { // expression is "1*x" or "x*1" or "x/1"
00323         if(c==c1)
00324           t->rhs1(t->rhs2());
00325         t->rhs2(NULL);
00326         t->op(NULL);
00327       }
00328     }
00329   }
00330 
00331   return t;
00332 } // at_threeAddr
00333 
00334 
00335 Node * constantFoldingChanger::at_basicblock(basicblockNode *the_bb,
00336                                                    Order ord) {
00337   return _current_block = the_bb;
00338 }
00339 
00340 
00341 Node * constantFoldingChanger::at_conditiongoto(conditiongotoNode *the_cg,
00342                                                       Order ord) {
00343   bool is_constant = false;
00344   bool which_branch;
00345 
00346   // -- Get the value of the condition
00347 
00348   // every conditiongotoNode should have a right and a op, but let's check
00349   // to be certain
00350   assert(the_cg->op());
00351   assert(the_cg->left());
00352   assert(the_cg->right());
00353 
00354   //take both the right hand and left hand sides
00355   indexNode * left = the_cg->left();
00356   indexNode * right = the_cg->right();
00357 
00358   //If they are both constant, evaluate and replace with appropriate action
00359   if(left->typ()==Const && right->typ() == Const) {
00360     constNode * l = (constNode *)left;
00361     constNode * r = (constNode *)right;
00362     constant lhs = l->value();
00363     constant rhs = r->value();
00364 
00365     //evaluate
00366     constant result = constant::eval(the_cg->op(), lhs, rhs);
00367     if(! result.no_val()) {
00368       is_constant = true;
00369       which_branch = result.Boolean();
00370     }
00371   }
00372 
00373   // -- If we can determine the outcome, replace the condition with the
00374   // appropriate branch.
00375   if (is_constant) {
00376     _changed = _cfg_changed = true;
00377     // choose appropriate branch - for true, want the goto.  for false, want
00378     // fall-through
00379 
00380 #define label_of_block(B) \
00381    ((B && !(B)->stmts().empty() && (B)->stmts().front()->typ() == Label) ? \
00382     (labelNode*) (B)->stmts().front() : NULL)
00383 
00384 #define erase_succ_pred(pred, succ) { \
00385   (pred)->succs().remove(succ); \
00386   (succ)->preds().remove(pred); \
00387   /* reflect change in comment. too troublesome to rebuild comment the way \
00388    * cfg does, so just append. */ \
00389   labelNode *l_succ = label_of_block(succ), \
00390             *l_pred = label_of_block(pred); \
00391   (pred)->comment() += " remove # "; \
00392   if(l_succ) (pred)->comment() += l_succ->name(); \
00393   (succ)->comment() += " remove # "; \
00394   if(l_pred) (succ)->comment() += l_pred->name(); \
00395 }
00396 
00397      basicblock_list succs = _current_block->succs();
00398 
00399      if(which_branch) {
00400        for(basicblock_list_p s=succs.begin(); s!=succs.end(); s++) {
00401          labelNode *label = label_of_block(*s);
00402          if(label != the_cg->label()) // erase
00403            erase_succ_pred (_current_block, *s)
00404        }
00405        return new gotoNode (the_cg->label());
00406      } else {
00407        for(basicblock_list_p s=succs.begin(); s!=succs.end(); s++) {
00408          labelNode *label = label_of_block(*s);
00409          if(label == the_cg->label()) { // erase
00410            erase_succ_pred (_current_block, *s)
00411            break;
00412          }
00413        }
00414        return NULL;
00415      }
00416   }
00417 
00418   return the_cg;
00419 } // at_conditiongoto
00420 
00421 
00423 
00424 void constantPropChanger::change() {
00425   for (unit_list_p n=CBZ::Program.begin(); n!=CBZ::Program.end(); n++)
00426     change(*n);
00427 } // change
00428 
00429 
00430 void constantPropChanger::change(unitNode *u) {
00431   if(!u) return;
00432   for(def_list_p d=u->defs().begin(); d!=u->defs().end(); d++)
00433     if((*d)->typ() == Proc) change((procNode*) *d);
00434 } // change(unitNode)
00435 
00436 void constantPropChanger::change(procNode *p) {
00437   if(!p) return;
00438   udduChains *udchain = reachingDefinitionsWalker::analyze(p);
00439   constantPropChanger cpc(udchain);
00440   constantFoldingChanger cfc;
00441 
00442   bool first_time = true;
00443   do {
00444     cpc.reset();
00445     p->change (cpc);
00446     if(! cpc._changed && !first_time) // ensure folding is performed at least
00447       break;                          // once
00448     first_time = false;
00449 
00450     cfc.reset();
00451     p->change (cfc);
00452     if(! cfc._changed) break;
00453     if(cfc._cfg_changed) {
00454       delete udchain;
00455       udchain = reachingDefinitionsWalker::analyze(p); // recompute
00456       cpc._udchain = udchain;
00457     }
00458   } while(true); // repeat until fixpoint
00459 
00460   delete udchain;
00461 } // change(procNode)
00462 
00464 
00465 void constantFoldingChanger::change() {
00466   for (unit_list_p n=CBZ::Program.begin(); n!=CBZ::Program.end(); n++)
00467     change(*n);
00468 } // change
00469 
00470 void constantFoldingChanger::change(unitNode *u) {
00471   if(!u) return;
00472   for(def_list_p d=u->defs().begin(); d!=u->defs().end(); d++)
00473     if((*d)->typ() == Proc) change((procNode*) *d);
00474 } // change(unitNode)
00475 
00476 void constantFoldingChanger::change(procNode *p) {
00477   if(!p) return;
00478   constantFoldingChanger cfc;
00479   p->change (cfc);
00480 } // change(procNode)
00481 
00483 
00484 class constpropphase : public Phase {
00485   void run() {
00486     constantPropChanger::change();
00487   }
00488 };
00489 Phases constprop_phase("constprop", new constpropphase());
00490 

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