Polaris: cdg_dag2tree.cc Source File

cdg_dag2tree.cc

Go to the documentation of this file.
00001 ///
00002 /// $Documentation Manager$ = "Doxygen"
00003 ///
00004 /*!
00005   \file dag2tree.cc
00006   \author Silvius Rus
00007   \date 9/19/00
00008   \brief Implementation for some functions defined in cdg.h
00009 */
00010 ///
00011 ///
00012 ///
00013 #include <list.h>
00014 #include <set.h>
00015 #include <algorithm>
00016 
00017 #include "Directive/RecurrenceAssertion.h"
00018 #include "Directive/AssertLoopLabel.h"
00019 
00020 #include "cdg/cdg_types.h"
00021 #include "cdg/cdg.h"
00022 
00023 #include "Statement/Statement.h"
00024 #include "Statement/LabelStmt.h"
00025 #include "ProgramUnit.h"
00026 #include "Directive/AssertComment.h"
00027 
00028 #include <exception>
00029 
00030 /// Clones node and links the clone to the given parent.
00031 /// It is recursive.  it assumes node is a tree root (it won't fail for a
00032 /// dag but will result in infinite cycle if the graph is cyclic).
00033 void cdg_clone(CDGNode* node, CDGNode* parent, bool value){
00034 
00035 /// Sanity check.
00036   p_assert(node, "Null CDG node to be cloned.");
00037 
00038 /// create the clone
00039 /// do not clone the statements.  we will clone them anyway when
00040 /// we restore the cfg (in cdg2cfg).
00041   CDGNode* clone=new CDGNode(node->cfgnode());
00042   
00043 /// link it to the parent
00044   CDSet pred;
00045   CDElement newcde(parent, value);
00046   pred.ins(newcde);
00047   clone->ins(pred);
00048   
00049 /// add all its children to the newly created node recursively
00050   for( Iterator<CDElement> cdit=node->outs(); cdit.valid(); ++cdit){
00051     cdg_clone(cdit.current().node(), clone, cdit.current().value());
00052   }
00053 }
00054 
00055 
00056 /// simple struct needed to walk up the CDG DAG.
00057 typedef struct __cdg_ws_node{
00058   CDGNode* node;
00059   int outdeg;
00060 } _cdg_ws_node;
00061 
00062 
00063 
00064 
00065 /// Assumes the CDG has no cycles other then self-loops.
00066 /// call "detect_cdg_cycles(pgm)" if you need to check that.
00067 /// Modifies the CDG from a DAG to a tree (if it is not already one).
00068 void cdg_dag2tree(ProgramUnit& pgm){
00069   clear_cdg_visited(pgm);
00070   int nnodes=pgm.stmts().entries();
00071   vector<_cdg_ws_node> all;
00072   int i=0;
00073   for (Iterator<Statement> stit=pgm.stmts().iterator();stit.valid();++stit){
00074     CDGNode* node=stit.current().cdgnode();
00075     _cdg_ws_node ws;
00076     ws.node=node;
00077     ws.outdeg=node->outs().entries();
00078     if (cdg_self_loop(node)){
00079       ws.outdeg--;
00080     }
00081     all.push_back(ws);
00082     node->visited(i);
00083     i++;
00084   }
00085 
00086   list<int> todo;  
00087 /// initialize work queue
00088   for (i=0;i<nnodes;i++){
00089     if (all[i].outdeg==0){
00090       todo.push_back(i);
00091     }
00092   }
00093 
00094   while (todo.size()!=0){
00095     int which=todo.front();
00096     todo.pop_front();
00097     CDGNode* node=all[which].node;
00098     RefList<CDElement> to_del;
00099     int at_first=1;
00100     for (Iterator<CDElement> cdit=node->ins();cdit.valid();++cdit){
00101       CDGNode* pred=cdit.current().node();
00102       if (pred==node) continue; /// ...  self loops are not interesting right now
00103       if (at_first){
00104     at_first=0;
00105     continue; /// ...  don't clone for this one, it's the first parent
00106       } else {
00107 
00108     /// ...  remove all other parents from predecessor list.
00109     to_del.ins_first(cdit.current());
00110 
00111     /// ...  remove it from this parent's successors list
00112     for(Iterator<CDElement> cdit2=pred->outs();cdit2.valid();++cdit2){
00113       if (cdit2.current().node()==node){
00114         pred->outs().del(cdit2.current());
00115         break;
00116       }
00117     }
00118 
00119     /// ...  clone this node (with the whole subtree) and link it to this parent
00120     cdg_clone(node, pred, cdit.current().value());
00121     
00122     /// ...  look at the predecessor and check whether it is time
00123     /// ...  to put it in the work queue (has no unvisited predecessors).
00124     int which_pred=pred->visited();
00125     if (all[which_pred].outdeg==0){
00126       todo.push_back(which_pred);
00127     }
00128       }
00129     }
00130     /// ...  remove from ins all the parents that have been given clones as children
00131     for (Iterator<CDElement> cdit=to_del;cdit.valid();++cdit){
00132       node->ins().del(cdit.current());
00133     }
00134   }
00135 }
00136 
00137 
00138 /// sort the nodes in the given vector based on the postdominance relation
00139 /// it assumes the nodes are completely ordered by this relation (they are 
00140 /// on a path from the root to a leaf).
00141 /// none of the nodes can be 0.
00142 void sort_pdt(vector<CDGNode*>& nodes){
00143   unsigned int size=nodes.size();
00144   unsigned int i,j;
00145 
00146 /// define a comparison table
00147   vector<int> zero(size,0);
00148   vector<vector<int> > table(size,zero);
00149 /// this thing can be done more efficiently using disjoint sets but I am in 
00150 /// a hurry now.  reconsider it if we need performance.
00151   for (i=0;i<size;i++){
00152     for (j=0;j<size;j++){
00153       if (i==j) continue;
00154 ///       cerr<<"\n i="<<*nodes[i]->cfgnode()
00155 ///       <<", j="<<*nodes[j]->cfgnode();
00156       
00157       if (postdominates(nodes[i],nodes[j])){
00158 ///     cerr<<"\n\tTRUE";
00159     table[i][j]=1;
00160       } else {
00161 ///     cerr<<"\n\tFALSE";
00162       }
00163     }
00164   }
00165 /// at this step it found all the relations.
00166   vector<CDGNode*> result(size);
00167 /// this vector will hold the mapping of positions in the sorted vector
00168   vector<int> pos(size,0);
00169   for (i=0;i<size;i++){
00170     for (j=0;j<size;j++){
00171       pos[i]+=table[i][j];
00172     }
00173     result[pos[i]]=nodes[i];
00174   }
00175   nodes=result;
00176 }
00177 
00178 
00179 /// Put all the children on the TRUE branch in PDT order.
00180 void get_trues(CDGNode* node, vector<CDGNode*>& trues){
00181   if (node->outs().entries()==0){
00182     return;
00183   }
00184   for (CDElement* cdit=node->outs().last_ref(); cdit; 
00185        cdit=(CDElement*)cdit->prev_ref()){
00186     if (cdit->node()==node) continue; /// ...  skip myself
00187     Statement& stmt=*(cdit->node()->cfgnode());
00188     switch(stmt.stmt_class()){
00189     case ENDDO_STMT:
00190     case IMPLIED_GOTO_STMT:
00191     case ENTRY_STMT:
00192     case ENDIF_STMT:
00193     case ELSE_STMT:
00194     case RETURN_STMT:
00195     case LABEL_STMT:
00196     case GOTO_STMT:
00197       continue;
00198     default:
00199       break;
00200     }
00201     if (!cdit->value()) trues.push_back(cdit->node());
00202   }
00203   sort_pdt(trues);
00204 }
00205 
00206 void write(vector<CDGNode*>& v, ostream& o);
00207 
00208 /// Put all the children on the FALSE branch in PDT order.
00209 void get_falses(CDGNode* node, vector<CDGNode*>& falses ){
00210   if (node->outs().entries()==0){
00211     return;
00212   }
00213   for (CDElement* cdit=node->outs().last_ref(); cdit; 
00214        cdit=(CDElement*)cdit->prev_ref()){
00215     if (cdit->node()==node) continue; /// ...  skip myself
00216     Statement& stmt=*(cdit->node()->cfgnode());
00217 ///     cerr<<"\n Now at false: "<<stmt;
00218     switch(stmt.stmt_class()){
00219     case ENDDO_STMT:
00220     case IMPLIED_GOTO_STMT:
00221     case ENTRY_STMT:
00222     case ENDIF_STMT:
00223     case ELSE_STMT:
00224     case RETURN_STMT:
00225     case LABEL_STMT:
00226     case GOTO_STMT:
00227       continue;
00228     default:
00229       break;
00230     }
00231 ///     cerr<<"\nPushing back cdgnode: "<<cdit->node();
00232     if (cdit->value()) falses.push_back(cdit->node());
00233   }
00234 ///   cerr<<"\nFalses before sorting:";
00235 ///   write(falses, cerr);
00236   
00237   sort_pdt(falses);
00238 }
00239 
00240 
00241 static set<String> _loop_labels;
00242 
00243 inline void copy_directives(Statement& from, Statement& to){
00244   static unsigned llc=0;
00245   to.pre_directives()=from.pre_directives();
00246   to.post_directives()=from.post_directives();
00247   to.assertions()=from.assertions();
00248   
00249 /// Modify loop label if DO stmt.
00250   if (to.stmt_class()==DO_STMT){
00251     for(Iterator<Assertion> iter = to.assertions(); iter.valid(); ++iter) {
00252       if (iter.current().type() == AS_LOOPLABEL) {
00253     AssertLoopLabel &a = (AssertLoopLabel &) iter.current();
00254     p_assert(a.string_arg_list_valid(),
00255          "Loop Label assertion with no valid name");
00256     p_assert(a.string_arg_list_guarded().entries() == 1,
00257          "Only supporting Loop Label assertions with 1 field");
00258     String old_label=a.string_arg_list_guarded()[0];
00259     String new_label;
00260     if (_loop_labels.find(old_label)==_loop_labels.end()){
00261       // First copy.
00262       new_label=old_label;
00263       _loop_labels.insert(new_label);
00264     } else {
00265       // Additional copy.
00266       strstream oldname;
00267       oldname<<old_label<<"_"<<llc++<<'\0';
00268       const char* s=oldname.str();
00269       new_label=s;
00270       oldname.freeze(0);
00271     }
00272     a.string_arg_list_guarded()[0]=new_label;
00273       }
00274     }
00275   }
00276 }
00277 
00278 void cdg_self_loop(CDGNode* root, bool& is_loop, bool& inside_predicate){
00279   is_loop=false;
00280   inside_predicate=false;
00281   for (Iterator<CDElement> cdit=root->outs(); cdit.valid(); ++cdit){
00282     CDGNode* next=cdit.current().node();
00283     if (next==root){
00284       is_loop=true;
00285       inside_predicate=cdit.current().value();
00286       return;
00287     }
00288   }
00289   return;
00290 }
00291 
00292 
00293 /// Removes '\n' from given line.
00294 inline void clean_line(const char* l, String& cl){
00295   const char* pc=l;
00296   char one[]="*";
00297   while (*pc){
00298     if (*pc!='\n'){
00299       one[0]=*pc;
00300       cl+=one;
00301     }
00302     ++pc;
00303   }
00304 }
00305 
00306 /// Inserts the statements in the tree below "node" after "ref"
00307 /// Returns the last statement inserted.
00308 /// It assumes that any GOTO loops have been identified and transformed
00309 /// into DO or WHILE loops
00310 Statement* cdg2cfg(CDGNode* node, Statement* ref, ProgramUnit& pgm){
00311 ///   cerr<<"\n Now at node: "<<*node->cfgnode();
00312   vector<CDGNode*> trues;
00313   get_trues(node, trues);
00314   vector<CDGNode*> falses;
00315   get_falses(node, falses);
00316 ///   cerr<<"\nFalses:";
00317 ///   write(falses, cerr);
00318 
00319   Statement* where=ref;
00320   Statement& stmt=*(node->cfgnode());
00321   if (node->outs().entries()==0){
00322     /// ...  This is a leaf.
00323     /// ...  Ignore a few specific types of statements.
00324     switch(stmt.stmt_class()){
00325     case ENDDO_STMT:
00326     case ENTRY_STMT:
00327     case IMPLIED_GOTO_STMT:
00328     case ENDIF_STMT:
00329     case ELSE_STMT:
00330     case RETURN_STMT:
00331     case LABEL_STMT:
00332     case GOTO_STMT:
00333       /// ...  Ignore it.
00334       return ref;
00335     case DO_STMT:
00336       /// ...  To add other cases.
00337       /// ...  This would be an error.
00338       cerr<<stmt;
00339       p_abort("Abnormal type of statement as CDG leaf.");
00340       return ref;
00341     case STOP_STMT: 
00342       /// ...  For now, leave the STOP statements here.
00343       /// ...  They have interprocedural effects.
00344     default:
00345       pgm.stmts().ins_after(stmt.clone(),ref);
00346       return ref->next_ref();
00347     }
00348   }
00349 
00350   bool is_loop;
00351   bool inside_predicate;
00352   cdg_self_loop(node, is_loop, inside_predicate);
00353 
00354   if (is_loop){
00355     Statement* where_else_is=0;
00356     if (inside_predicate){
00357       /// ...  Insert false children.
00358       for (unsigned int i=0;i<falses.size();i++){
00359     where=cdg2cfg(falses[i],where,pgm);
00360       }
00361       where_else_is=where;
00362       /// ...  Insert true children.
00363       for (unsigned int i=0;i<trues.size();i++){
00364     where=cdg2cfg(trues[i],where,pgm);
00365       }
00366     } else {
00367       /// ...  Insert true children.
00368       for (unsigned int i=0;i<trues.size();i++){
00369     where=cdg2cfg(trues[i],where,pgm);
00370       }
00371       /// ...  Insert false children.
00372       where_else_is=where;
00373       for (unsigned int i=0;i<falses.size();i++){
00374     where=cdg2cfg(falses[i],where,pgm);
00375       }
00376     }
00377 
00378 
00379     /// ...  Analyze this current node.
00380     switch(stmt.stmt_class()){
00381     case WRITE_STMT:
00382     case READ_STMT:
00383       pgm.stmts().ins_after(stmt.clone(),ref);
00384       return ref->next_ref();
00385     case IF_STMT:
00386     case ELSEIF_STMT:{
00387       /// ...  Wrap a WHILE around the children on the same edge value as the
00388       /// ...  self loop and let the others out.
00389       Expression* predicate=stmt.expr().clone();
00390       if (inside_predicate==true){
00391     predicate=simplify(not(predicate));
00392       }
00393       /// ...  Check whether loop is empty.  If so, add a label inside.
00394       if (ref==where_else_is){
00395     Statement* dl=new LabelStmt(pgm.stmts().new_tag(),
00396                     pgm.stmts().new_label());
00397     pgm.stmts().ins_after(dl, ref);
00398     where_else_is=dl;
00399       }
00400       
00401       String comment="";
00402       for (Iterator<Assertion> ait=stmt.assertions(); ait.valid(); ++ait){
00403     if (ait.current().type()==AS_RECURRENCE){
00404       RecurrenceAssertion& ra=(RecurrenceAssertion&)ait.current();
00405       comment+=ra.ra_string_arg_list_guarded()[0];
00406     }
00407       }
00408       if (comment==""){
00409     strstream s;
00410     int w=1;
00411     stmt.write(s,w);
00412     s<<'\0';
00413     clean_line(s.str(), comment);
00414     s.freeze(0);
00415       }
00416       Statement& clone=pgm.stmts().ins_WHILE_after(predicate, 
00417                            ref, where_else_is);
00418       AssertComment* newassert=new AssertComment();
00419       newassert->string_arg_list_guarded().
00420     ins_last(new StringElem(comment));
00421       clone.assertions().ins_last(newassert);
00422       return ref->next_ref()->follow_ref();
00423     }
00424     case DO_STMT:
00425       if (ref==where){ /// ...  empty do body
00426     Statement* dummy=new LabelStmt(pgm.stmts().new_tag(),
00427                        pgm.stmts().new_label());
00428     pgm.stmts().ins_after(dummy,ref);
00429     where=dummy;
00430     Statement& clone=pgm.stmts().ins_DO_after(stmt.index().clone(),
00431                           stmt.init().clone(),
00432                           stmt.limit().clone(),
00433                           stmt.step().clone(),
00434                           ref, where);
00435     copy_directives(stmt,clone);
00436     pgm.stmts().del(*dummy);
00437     return ref->next_ref()->next_ref();
00438       } else {
00439     Statement& clone=pgm.stmts().ins_DO_after(stmt.index().clone(),
00440                           stmt.init().clone(),
00441                           stmt.limit().clone(),
00442                           stmt.step().clone(),
00443                           ref, where);
00444     copy_directives(stmt,clone);
00445     return ref->next_ref()->follow_ref();
00446       }
00447       break;
00448     case WHILE_STMT:
00449       if (ref==where){ /// ...  empty while body
00450     Statement* dummy=new LabelStmt(pgm.stmts().new_tag(),
00451                        pgm.stmts().new_label());
00452     pgm.stmts().ins_after(dummy,ref);
00453     where=dummy;
00454     Statement& clone=pgm.stmts().ins_WHILE_after(stmt.expr().clone(), 
00455                              ref, where);
00456     copy_directives(stmt,clone);
00457     pgm.stmts().del(*dummy);
00458     return where->next_ref()->follow_ref();
00459       } else {
00460     Statement& clone=pgm.stmts().ins_WHILE_after(stmt.expr().clone(), 
00461                              ref, where);
00462     copy_directives(stmt,clone);
00463     return ref->next_ref()->follow_ref();
00464       }
00465       break;
00466     default:
00467       /// ...  This statement cannot be a CDG internal node, since the only types 
00468       /// ...  of CFG branches are above.  The other types of branching statements
00469       /// ...  should have been transformed into one (or more) of the above.
00470       cerr<<"Unknown branch type encountered in the following statement:";
00471       stmt.print(cerr);
00472       p_abort("Fatal error in IPA_CDG: see above message");
00473       return ref;
00474     }
00475   } else {
00476     /// ...  This is not a loop, must be IF, ELSEIF or FLOW_ENTRY.
00477 
00478     /// ...  Insert true children.
00479     for (unsigned int i=0;i<trues.size();i++){
00480       where=cdg2cfg(trues[i],where,pgm);
00481     }
00482     
00483     /// ...  Insert false children.
00484     Statement* where_else_is=where;
00485     for (unsigned int i=0;i<falses.size();i++){
00486       where=cdg2cfg(falses[i],where,pgm);
00487     }
00488   
00489 
00490     /// ...  Analyze this current node.
00491     switch(stmt.stmt_class()){
00492     case IF_STMT:
00493     case ELSEIF_STMT:
00494       if (trues.size()==0){
00495     if (falses.size()==0){
00496       // This case is an empty IF (IF (...) THEN ENDIF)
00497       // Polaris has some bug when I try to create an empty IF stmt
00498       // so I will do a trick: insert a dummy label, insert the if
00499       // around it then delete the label.
00500       Statement* dummy=new LabelStmt(pgm.stmts().new_tag(),
00501                      pgm.stmts().new_label());
00502       pgm.stmts().ins_after(dummy,ref);
00503       where=ref->next_ref();
00504       pgm.stmts().ins_IF_after(not(stmt.expr().clone()),ref,where);
00505       // remove the dummy label
00506 ///       pgm.stmts().del(*dummy);
00507       return ref->next_ref()->matching_endif_ref();
00508     } else {
00509 ///       cerr<<"\nref: "<<*ref
00510 ///           <<"\nwhere: "<<*where;
00511       pgm.stmts().ins_IF_after(not(stmt.expr().clone()),ref,where);
00512       return ref->next_ref()->matching_endif_ref();
00513     }
00514       } else {
00515     if (falses.size()>0){
00516       // Insert an IF_ELSE_ENDIF
00517       pgm.stmts().ins_IF_ELSE_after(stmt.expr().clone(),ref, where_else_is,where);
00518       return ref->next_ref()->matching_endif_ref();
00519     } else {
00520       // Insert an IF_ENDIF
00521       pgm.stmts().ins_IF_after(stmt.expr().clone(),ref,where);
00522       return ref->next_ref()->matching_endif_ref();
00523     }
00524       }
00525       break;
00526     case FLOW_ENTRY_STMT:
00527       return ref;
00528     case READ_STMT:
00529     case WRITE_STMT:
00530     case PRINT_STMT:
00531     case OPEN_STMT:
00532     case CLOSE_STMT:
00533     case REWIND_STMT:
00534     case BACKSPACE_STMT:
00535     case ENDFILE_STMT:
00536     case INQUIRE_STMT:
00537       cerr<<"\nThe restructurer cannot handle for now I/O exception"
00538       <<"\nhandling constructs.  The following statement at line "
00539       <<stmt.line()<<",\nin file "<<pgm.original_file_ref()
00540       <<" contains such a construct: \n";
00541       {
00542     int w=1;
00543     stmt.write(cerr, w);
00544       }
00545       p_warning("Non-fatal error in CDG2CFG: see message above.");
00546       throw bad_exception();
00547 
00548     default:
00549       /// ...  This statement cannot be a CDG internal node, since the only types 
00550       /// ...  of CFG branches are above.  The other types of branching statements
00551       /// ...  should have been transformed into one (or more) of the above.
00552       cerr<<"Unknown branch type encountered in the following statement:";
00553       stmt.print(cerr);
00554       p_abort("Fatal error in CDG2CFG: see above message");
00555       return ref;
00556     }
00557   }
00558 }
00559 
00560 
00561 /// Removes cdg node associated with current statement.
00562 static void uncdg(Statement* stmt){
00563   CDGNode* cdgnode=stmt->cdgnode();
00564   if (cdgnode) {
00565     delete cdgnode;
00566     stmt->cdgnode(0);
00567   }
00568 }  
00569  
00570 
00571 /// Removes old information from the only original statements.
00572 /// They are FLOW_ENTRY, ENTRY and FLOW_EXIT.
00573 /// Will remove the cdg nodes if they exist.
00574 static void custom_cleanup(ProgramUnit& pgm){
00575   uncdg(pgm.stmts().first_ref());
00576   uncdg(pgm.stmts().first_ref()->next_ref());
00577   uncdg(pgm.stmts().last_ref());
00578   _loop_labels.clear();
00579 }
00580 
00581 
00582 /// Rewrites the CFG from the CDG.
00583 void cdg2cfg(ProgramUnit& pgm){
00584 
00585 /// Initialize loop label repository.
00586   _loop_labels.clear();
00587 
00588 /// Save start of old statement list, skip FLOW_ENTRY and ENTRY.
00589   Statement* old_start=pgm.stmts().first_ref()->next_ref()->next_ref();
00590 ///   cerr<<"\nold_start: "<<*old_start;
00591 
00592 /// Insert statements for all nodes recursively.
00593   cdg2cfg(pgm.stmts().first_ref()->cdgnode(),
00594       pgm.stmts().first_ref()->next_ref(),pgm);
00595 
00596 ///   pgm.write(cerr);
00597 ///   cerr<<"\nold_start: "<<*old_start;
00598   
00599 /// Remove original statements.
00600   pgm.stmts().del(*old_start,*(pgm.stmts().last_ref()->prev_ref()));
00601 
00602 /// Do some custom cleanup.
00603   custom_cleanup(pgm);
00604 }
 © 1995-2005 University of Illinois, Urbana-Champaign. All rights reserved.  Fri Mar 25 23:05:41 2005