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  

copyprop.cc

Go to the documentation of this file.
00001 // ----------------------------------------------------------------------
00002 //
00003 //  C-Breeze
00004 //  C Compiler Framework
00005 // 
00006 //  Copyright (c) 2000 University of Texas at Austin
00007 // 
00008 //  Teck Bok Tok
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 "copyprop.h"
00039 #include "bits.h"
00040 
00041 // helper class to obtain copies and ambiguous
00042 class copyPropChanger::GetDefsWalker : public Walker {
00043 private:
00044 
00045   threeAddr_set * copies, // copy statements
00046                 * ambiguous_defs; // list of ambiguous definitions, passed in
00047   map<threeAddrNode*,declNode*> *defines; // what does statement define?
00048 
00049 public:
00050   GetDefsWalker (threeAddr_set *c, threeAddr_set *l,
00051                  map<threeAddrNode*,declNode*> *d) : 
00052     Walker (Preorder, Subtree), ambiguous_defs(l), copies(c), defines(d) { }
00053 
00054   void at_threeAddr (threeAddrNode *stmt, Order) {
00055     bool ambiguous = false;
00056     if(stmt->lhs()) {
00057       operandNode *lhs = stmt->lhs();
00058       if(lhs->star() || ! lhs->fields().empty() || lhs->index())
00059         // note: possible future work: allow lhs fields.
00060         ambiguous = true;
00061       else {
00062         assert(lhs->var()->typ() == Id);
00063         (*defines)[stmt] = ((idNode*)lhs->var())->decl();
00064         if(!stmt->rhs2() &&
00065            (!stmt->op() || stmt->op()->id() == Operator::UPLUS)) {
00066           operandNode *rhs = stmt->rhs1();
00067           if(rhs->var()->typ()==Id && !rhs->star() && rhs->fields().empty() &&
00068              !rhs->index() && !rhs->cast() && !rhs->addr())
00069             copies->insert(stmt);
00070         }
00071       }
00072     }
00073     if(stmt->op() && stmt->op()->id() == Operator::FUNC_CALL)
00074       ambiguous = true;
00075     if(ambiguous)
00076       ambiguous_defs->insert (stmt);
00077   }
00078 }; // class GetDefsWalker
00079 
00081 
00082 // flow value
00083 class copyPropChanger::copyFlowVal {
00084 private:
00085 
00086   map<threeAddrNode*, int> def2num; // a map from a definition to its
00087                                     // index (bit position)
00088   map<int, threeAddrNode*> num2def; // a map from index to definition.
00089   int                      size;    // the number of definitions
00090   Bits                    *bits;
00091 
00092   static threeAddr_set    dummies;
00093 
00094 public:
00097   copyFlowVal (threeAddr_set copy_stmts, threeAddr_set ambiguous_defs) {
00098     // get all variables.
00099     decl_set vars;
00100     for(threeAddr_set_p s=copy_stmts.begin(); s!=copy_stmts.end();s++)
00101       vars.insert( ((idNode*) (*s)->lhs()->var())->decl() );
00102 
00103     // We need one bit for each variable (for arbiguous definitions) and
00104     // each copy statement.
00105     size = copy_stmts.size() + vars.size();
00106     bits = new Bits(size+1);
00107 
00108     // unambiguous copy statements
00109     int i=1;
00110     for(threeAddr_set_p s=copy_stmts.begin(); s!=copy_stmts.end();
00111         s++, i++) {
00112       def2num[*s] = i;
00113       num2def[i] = *s;
00114     }
00115 
00116     // ambiguous definitions: create one dummy for each var
00117     for (decl_set_p v=vars.begin(); v!=vars.end(); v++, i++) {
00118       threeAddrNode *dummy = new threeAddrNode (NULL,(operandNode*)NULL);
00119       dummies.insert(dummy);
00120       def2num[dummy] = i;
00121       num2def[i] = dummy;
00122     }
00123 
00124     to_top ();
00125   } // constructor
00126 
00127   ~copyFlowVal (void) { delete bits; }
00128 
00130   void to_top (void) { bits->reset_all(); }
00131 
00132   void to_bottom(void) { bits->set_all(); }
00133 
00135   copyFlowVal * clone (void) const {
00136     copyFlowVal *other = new copyFlowVal (*this);
00137     other->bits = bits->clone();
00138     return other;
00139   }
00140 
00141   // get all statements represented by this flow value.
00142   inline threeAddr_set stmts(void ) {
00143     threeAddr_set l;
00144     for (int i=1; i<=size; i++)
00145       if(in(i)) l.insert(num2def[i]);
00146     return l;
00147   }
00148 
00150   bool diff (copyFlowVal *other) const {
00151     if(! other) return true;
00152     for (int i=1; i<=size; i++)
00153       if (other->bits->value(i) != bits->value(i)) 
00154         return true;
00155     return false;
00156   }
00157 
00158   // return true if the definition is in the set, by a pointer to the definition
00159   bool in (threeAddrNode *s) { return bits->value(def2num[s]); }
00160 
00161   // return true if the definition is in the set, by the index of the definition
00162   bool in (int i) const { return bits->value(i); }
00163 
00165   void insert (threeAddrNode *s) { bits->set (def2num[s], true); }
00166 
00168   void insert (int i) { bits->set (i, true); }
00169 
00171   void remove (threeAddrNode *s) { bits->set (def2num[s], false); }
00172 
00174   void remove (int i) { bits->set (i, false); }
00175 
00177   void copy (copyFlowVal *other) { if(other) bits->copy (other->bits); }
00178 
00180   void Union (const copyFlowVal *v) { if(v) bits->Or (v->bits); }
00181 
00183   void Intersect (const copyFlowVal *v) { if(v) bits->And (v->bits); }
00184 
00185   // set this definition to the set difference of itself with the
00186   // parameter (i.e. this - the other)
00187   void Difference (copyFlowVal *other) {
00188     if(!other) return;
00189     Bits comp(size+1);
00190     comp.copy (other->bits);
00191     comp.Not ();
00192     bits->And (&comp);
00193   }
00194 
00196   void meet (const copyFlowVal *v) { Union(v); }
00197 
00198   void print() {
00199     cout << "{";
00200     for (int i=1; i<=size; i++) if(in(i)) cout << i << ",";
00201     cout << "}";
00202   }
00203 
00204   static void clear_dummies() {
00205     for(threeAddr_set_p t=dummies.begin(); t!=dummies.end(); t++)
00206       delete *t;
00207     dummies.clear();
00208   }
00209 }; // copyFlowVal
00210 
00211 copyPropChanger::threeAddr_set copyPropChanger::copyFlowVal::dummies;
00212 
00214 
00215 Node *copyPropChanger::at_proc(procNode *p, Order ord) {
00216   if(!p) return p;
00217 
00218   // get the copy statements and ambiguous definitions from this procedure
00219 
00220   GetDefsWalker gdw(&copies, &ambiguous, &defines);
00221   p->walk(gdw);
00222 
00223   // create flow value
00224   _top = new copyFlowVal(copies, ambiguous);
00225   _bottom = _top->clone();
00226   _bottom->to_bottom();
00227 
00228   // if the first block has a label, we need a preheader to receive gen
00229   // for the parameters and globals
00230 
00231   basicblockNode *b = (basicblockNode *) p->body()->stmts().front();
00232   if (b->stmts().size() && b->stmts().front()->typ() == Label) {
00233     // new Goto to the first block
00234     stmt_list new_stmt;
00235     new_stmt.push_back( new gotoNode((labelNode*) b->stmts().front()) );
00236 
00237     b = new basicblockNode (NULL, & new_stmt);
00238     b->comment() = "preheader to generate parameters and globals";
00239   
00240     // link it to the first block in the procedure
00241   
00242     ((basicblockNode *)(p->body()->stmts().front()))->
00243       preds().push_back (b);
00244     b->succs().push_back ((basicblockNode *) 
00245       p->body()->stmts().front());
00246     p->body()->stmts().push_front (b);
00247   }
00248 
00249   stmt_list stmts = p->body()->stmts();
00250 
00251   // start global phase. It works on all basic blocks.
00252 
00253   for(stmt_list_p s=stmts.begin(); s!=stmts.end(); s++) {
00254     assert( (*s)->typ() == Block);
00255     basicblockNode *b = (basicblockNode*) *s;
00256     Gen[b] = create_copy_set(b);
00257   }
00258   for(stmt_list_p s=stmts.begin(); s!=stmts.end(); s++) {
00259     basicblockNode *b = (basicblockNode*) *s;
00260     Kill[b] = create_kill_set(b, stmts);
00261   }
00262 
00263   solve_global_dataflow(stmts);
00264 
00265   // now local phase. It works on statements in each basic block.
00266   for(stmt_list_p s=stmts.begin(); s!=stmts.end(); s++) {
00267     basicblockNode *b = (basicblockNode*) *s;
00268     local_copy_prop(b);
00269   }
00270 
00271   // clean up
00272   copies.clear();  ambiguous.clear();  defines.clear();
00273   set<copyFlowVal*> flowvals;
00274   for(map<basicblockNode*, copyFlowVal*>::iterator m=Gen.begin();
00275       m!=Gen.end(); m++) if(m->second) flowvals.insert(m->second);
00276   for(map<basicblockNode*, copyFlowVal*>::iterator m=Kill.begin();
00277       m!=Kill.end(); m++) if(m->second) flowvals.insert(m->second);
00278   for(map<basicblockNode*, copyFlowVal*>::iterator m=In.begin();
00279       m!=In.end(); m++) if(m->second) flowvals.insert(m->second);
00280   for(map<basicblockNode*, copyFlowVal*>::iterator m=Out.begin();
00281       m!=Out.end(); m++) if(m->second) flowvals.insert(m->second);
00282   if(_top) flowvals.insert(_top);
00283   if(_bottom) flowvals.insert(_top);
00284   for(set<copyFlowVal*>::iterator f=flowvals.begin(); f!=flowvals.end(); f++)
00285     delete *f;
00286   Gen.clear();  Kill.clear();  In.clear();  Out.clear();
00287   copyFlowVal::clear_dummies();
00288 
00289   return p;
00290 } // at_proc
00291 
00293 // global phase
00294 
00295 copyPropChanger::copyFlowVal *
00296 copyPropChanger::create_copy_set(basicblockNode *b) {
00297   // compute the set of copy statements "a=b" in the block b where nether a nor
00298   // b is assigned-to later in block.
00299   if(!b) return _top;
00300 
00301   threeAddr_set copy_stmts;
00302   for(stmt_list_p s=b->stmts().begin(); s!=b->stmts().end(); s++) {
00303     if((*s)->typ() != ThreeAddr) continue;
00304     threeAddrNode *t = (threeAddrNode*) *s;
00305     if(ambiguous.find(t) != ambiguous.end()) {
00306       copy_stmts.clear(); // kill all
00307       continue;
00308     }
00309     if(! defines[t]) continue;
00310     for(threeAddr_set_p c=copy_stmts.begin(); c!=copy_stmts.end(); ) {
00311       bool kill_c = false; // kill c if t defines lhs or rhs of c.
00312       if(defines[*c] == defines[t]) kill_c = true;
00313       else {
00314         idNode *rhs = (idNode*) (*c)->rhs1()->var();
00315         if(rhs->decl() == defines[t]) kill_c = true;
00316       }
00317       if(kill_c) { threeAddrNode *C = *c;  c++;  copy_stmts.erase(C); }
00318       else c++;
00319     }
00320     if(copies.find(t) != copies.end())
00321       copy_stmts.insert(t);
00322   }
00323 
00324   if(copy_stmts.empty()) return _top;
00325   copyFlowVal *fv= _top->clone();
00326   for(threeAddr_set_p c=copy_stmts.begin(); c!=copy_stmts.end(); c++)
00327     fv->insert(*c);
00328   return fv;
00329 } // create_copy_set
00330 
00331 
00332 copyPropChanger::copyFlowVal *
00333 copyPropChanger::create_kill_set(basicblockNode *b, stmt_list bbs) {
00334   // compute the set of copy statements outside of b and get killed by b.
00335   if(!b) return _top;
00336 
00337   // first, obtain all statements killed by b
00338   decl_set kill_vars;
00339   for(stmt_list_p s=b->stmts().begin(); s!=b->stmts().end(); s++) {
00340     if((*s)->typ() != ThreeAddr) continue;
00341     threeAddrNode *t = (threeAddrNode*) *s;
00342     if(ambiguous.find(t) != ambiguous.end())
00343       return _bottom; // kill all
00344 
00345     if(defines[t])
00346       kill_vars.insert(defines[t]);
00347   }
00348   if(kill_vars.empty()) return _top;  // kill nothing
00349 
00350   // now go through the Gen of all other blocks to obtain the Kill set of b.
00351   threeAddr_set kill_stmts;
00352   for(stmt_list_p o=bbs.begin(); o!=bbs.end(); o++) {
00353     if(*o == b) continue;
00354     basicblockNode *other = (basicblockNode*) *o;
00355     if(!Gen[other]) continue;  // other generates nothing
00356     threeAddr_set defs = Gen[other]->stmts();
00357     for(threeAddr_set_p d=defs.begin(); d!=defs.end(); d++)
00358       if(defines[*d] && kill_vars.find(defines[*d]) != kill_vars.end())
00359         kill_stmts.insert(*d);
00360   }
00361 
00362   if(kill_stmts.empty()) return _top; // kill nothing
00363   copyFlowVal *fv= _top->clone();
00364   for(threeAddr_set_p k=kill_stmts.begin(); k!=kill_stmts.end(); k++)
00365     fv->insert(*k);
00366   return fv;
00367 } // create_kill_set
00368 
00369 
00370 void copyPropChanger::solve_global_dataflow(stmt_list stmts) {
00371   // initialize
00372   for(stmt_list_p s=stmts.begin(); s!=stmts.end(); s++) {
00373     basicblockNode *B = (basicblockNode *) *s;
00374     In[B] = _top->clone();
00375     Out[B] = _top->clone();
00376   }
00377 
00378   stmt_list worklist = stmts; // repeat until fixpoint
00379 
00380   copyFlowVal *oldout = _top->clone();
00381   while (! worklist.empty()) {
00382     basicblockNode *B = (basicblockNode *) worklist.front();
00383     worklist.remove(B);
00384     copyFlowVal *inb = In[B],
00385                 *outb = Out[B];
00386 
00387     // In[B] = \Intersect_{q \in pred[B]} Out[q]
00388     if(B->preds().empty()) inb->to_top(); // is B the first block in proc?
00389     for (basicblock_list_p q=B->preds().begin(); q!=B->preds().end(); q++)
00390       if(q == B->preds().begin())
00391         inb->copy(Out[*q]);
00392       else
00393         inb->Intersect (Out[*q]);
00394 
00395     oldout->copy (outb); // save a copy
00396     // Out[B] = Gen[B] \U { In[B] - Kill[B] }
00397     outb->copy (inb);
00398     outb->Difference (Kill[B]);
00399     outb->Union (Gen[B]);
00400     if (oldout->diff(outb)) // change detected. put B's successors to worklist
00401       for (basicblock_list_p s=B->succs().begin(); s!=B->succs().end(); s++)
00402         if(find(worklist.begin(), worklist.end(), *s) == worklist.end())
00403           worklist.push_back(*s);
00404   }
00405   delete oldout;
00406 } // solve_global_dataflow
00407 
00409 // local phase
00410 
00411 void copyPropChanger::local_copy_prop(basicblockNode *b) {
00412   if(!b) return;
00413 
00414   ACP acp; // the set of available copy instructions ("statements")
00415   if(In[b]) { // initialize acp for b to what's in In[b].
00416     threeAddr_set in = In[b]->stmts();
00417     for(threeAddr_set_p i=in.begin(); i!=in.end(); i++) {
00418       operandNode *lhs = (*i)->lhs(), *rhs = (*i)->rhs1();
00419       assert(lhs && lhs->var()->typ()==Id);
00420       assert(rhs && rhs->var()->typ()==Id);
00421       acp.insert(Var_pair(((idNode*)lhs->var())->decl(),
00422                           ((idNode*)rhs->var())->decl()));
00423     }
00424   }
00425 
00426   // now go through statements in b, propagate copies.
00427   for(stmt_list_p s=b->stmts().begin(); s!=b->stmts().end(); s++) {
00428     switch((*s)->typ()) {
00429       case ThreeAddr: {
00430         threeAddrNode *t = (threeAddrNode*) *s;
00431         // perform propagation where possible.
00432         copy_value(t->rhs1(), acp);
00433         copy_value(t->rhs2(), acp);
00434         for(operand_list_p a=t->arg_list().begin(); a!=t->arg_list().end(); a++)
00435           copy_value(*a, acp);
00436 
00437         // update acp
00438         if(ambiguous.find(t) != ambiguous.end())
00439           acp.clear();  // clear, no more acp.
00440         else {
00441           operandNode *lhs = t->lhs();
00442           if(lhs && !lhs->star() && lhs->fields().empty() &&
00443              !lhs->index()) {
00444             // remove acp on the copy that involves the lhs.
00445             assert(lhs->var()->typ() == Id);
00446             remove_ACP(acp, ((idNode*)lhs->var())->decl());
00447           }
00448           if(copies.find(t) != copies.end()) { // t itself is also an acp
00449             operandNode *rhs = t->rhs1();
00450             assert(rhs && !rhs->star() && rhs->fields().empty() &&
00451                    !rhs->index() && rhs->var()->typ() == Id);
00452             acp.insert(Var_pair(((idNode*)lhs->var())->decl(),
00453                                 ((idNode*)rhs->var())->decl()));
00454           }
00455         }
00456         break;
00457       }
00458 
00459       // for Condition and Return, similar to ThreeAddr except there is no def.
00460       case Condition: {
00461         conditiongotoNode *g = (conditiongotoNode*) *s;
00462         assert(g->left());
00463         if(g->left()->typ()==Id) {
00464           idNode *new_id = copy_value((idNode*) g->left(), acp);
00465           if(new_id != g->left()) g->left(new_id);
00466         }
00467         assert(g->right());
00468         if(g->right()->typ()==Id) {
00469           idNode *new_id = copy_value((idNode*) g->right(), acp);
00470           if(new_id != g->right()) g->right(new_id);
00471         }
00472         break;
00473       }
00474 
00475       case Return: {
00476         // Note: procNode's return_decl() is not updated.
00477         // The optimization here will interfere with the backend, in different
00478         // ways depending on if the return_decl() is updated or not.
00479         returnNode *r = (returnNode*) *s;
00480         idNode *new_id = copy_value((idNode*) r->expr(), acp);
00481         if(new_id != r->expr())
00482           r->expr(new_id);
00483         break;
00484       }
00485 
00486       case Goto: case Label: break;
00487       case Expr: assert(! ((exprstmtNode*)*s)->expr());
00488                  break;
00489       default: assert(false); // unreachable
00490     }
00491   }
00492 } // local_copy_prop
00493 
00494 void copyPropChanger::remove_ACP(ACP &acp, declNode *v) {
00495   if(!v) return;
00496   for(ACP::iterator m=acp.begin(); m!=acp.end(); )
00497     if(m->first==v || m->second==v) {
00498       Var_pair p=*m;  m++;  acp.erase(p);  // remove pair
00499     } else m++;
00500 } // remove_ACP
00501 
00502 
00503 void copyPropChanger::copy_value(operandNode *opnd, const ACP &acp) {
00504   if(!opnd) return;
00505   // Q: allow fields or index?
00506   if(opnd->addr() /*|| !opnd->fields().empty() || opnd->index()*/) return;
00507   if(opnd->var()->typ() != Id) return;
00508   idNode *new_id = copy_value((idNode*) opnd->var(), acp);
00509   if(new_id != opnd->var())
00510     opnd->var(new_id);
00511   if(opnd->index() && opnd->index()->typ() == Id) {
00512     new_id = copy_value((idNode*) opnd->index(), acp);
00513     if(new_id != opnd->index())
00514       opnd->index(new_id);
00515   }
00516 } // copy_value(operandNode)
00517 
00518 
00519 idNode *copyPropChanger::copy_value(idNode *opnd, const ACP &acp) {
00520   if(!opnd) return opnd;
00521   declNode *decl = opnd->decl();
00522 
00523   decl_set copy_found;
00524   for(ACP::const_iterator m=acp.begin(); m!=acp.end(); m++)
00525     if(m->first==decl)
00526       copy_found.insert( m->second );
00527 
00528   if(copy_found.empty()) return opnd;
00529 
00530   if(copy_found.size() == 1)
00531     return new idNode(* copy_found.begin());
00532 
00533   assert(false); // not reachable, unless...big changes; essentially make
00534                  // duplicate but identical statements share same bit in flow
00535                  // value.
00536   for(decl_set_p c=copy_found.begin(); c!=copy_found.end(); c++)
00537     if(*c != * copy_found.begin())
00538       return opnd;  // no unit copy found
00539   // found unique copy
00540   return new idNode(* copy_found.begin());
00541 } // copy_value (idNode)
00542 
00544 
00545 void copyPropChanger::change() {
00546   for (unit_list_p n=CBZ::Program.begin(); n!=CBZ::Program.end(); n++)
00547     change(*n);
00548 } // change
00549 
00550 
00551 void copyPropChanger::change(unitNode *u) {
00552   if(!u) return;
00553   for(def_list_p d=u->defs().begin(); d!=u->defs().end(); d++)
00554     if((*d)->typ() == Proc) change((procNode*) *d);
00555 } // change(unitNode)
00556 
00557 void copyPropChanger::change(procNode *p) {
00558   if(!p) return;
00559   copyPropChanger cpc;
00560   p->change (cpc);
00561 } // change(procNode)
00562 
00564 
00565 class copypropphase : public Phase {
00566   void run() {
00567     copyPropChanger::change();
00568   }
00569 };
00570 Phases copyprop_phase("copyprop", new copypropphase());
00571 

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