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  

cfg.cc

Go to the documentation of this file.
00001 // $Id: cfg.cc,v 1.12 2003/08/07 23:14:07 pnav Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2000 University of Texas at Austin
00008 // 
00009 //  Samuel Z. Guyer
00010 //  Daniel A. Jimenez
00011 //  Calvin Lin
00012 // 
00013 //  Permission is hereby granted, free of charge, to any person
00014 //  obtaining a copy of this software and associated documentation
00015 //  files (the "Software"), to deal in the Software without
00016 //  restriction, including without limitation the rights to use, copy,
00017 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00018 //  of the Software, and to permit persons to whom the Software is
00019 //  furnished to do so, subject to the following conditions:
00020 //  
00021 //  The above copyright notice and this permission notice shall be
00022 //  included in all copies or substantial portions of the Software.
00023 //  
00024 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00026 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00028 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00029 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00030 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00031 //  THE SOFTWARE.
00032 //
00033 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00034 //  Computer Science for inspiring parts of the C-Breeze design.
00035 //
00036 // ----------------------------------------------------------------------
00037 //
00038 // cfg.cc
00039 //
00040 
00041 #include <stdio.h>
00042 #include "c_breeze.h"
00043 #include "dismantle.h"
00044 #include "goto_label_walker.h"
00045 #include "cfg.h"
00046 
00047 // At a procedure, do this:
00048 // 1. Separate the dismantled code into basic blocks so that the
00049 // body() of the procNode is a blockNode whose stmts() is a list of
00050 // basicblockNode's.
00051 //
00052 // 2. Find the preds and succs of each basic block to create a control
00053 // flow graph.
00054 //
00055 // So at the end of this function, the procedure will have a control
00056 // flow graph with a source at the first stmt in body()->stmts(),
00057 // and a sink (return) at the last stmt in body()->stmts().  This relies
00058 // on the dismantler having changed all return stmts into goto's to
00059 // the single return stmt at the end of the procedure.
00060 //
00061 
00062 class unreachableCodeRemover : public Walker {
00063 private:
00064         map<stmtNode *,bool> marked;
00065 
00066 public:
00067         unreachableCodeRemover (void) : Walker (Preorder, Subtree) { }
00068 
00069         void dfs (basicblockNode *n) {
00070                 basicblock_list_p p;
00071 
00072                 marked[n] = true;
00073                 for (p=n->succs().begin(); p!=n->succs().end(); p++) {
00074                         if (!marked[*p]) dfs (*p);
00075                 }
00076         }
00077 
00078         void fixup_preds (basicblockNode *b) {
00079                 basicblock_list_p p;
00080 
00081                 for (p=b->preds().begin(); p!=b->preds().end(); ) {
00082                         if (marked[*p])
00083                                 p++;
00084                         else
00085                                 p = b->preds().erase (p);
00086                 }
00087         }
00088 
00089         void at_proc (procNode *p, Order) {
00090                 marked.clear();
00091                 blockNode *b = p->body();
00092                 stmtNode *s = b->stmts().front();
00093                 assert (s->typ() == Block);
00094                 basicblockNode *bb = (basicblockNode *) s;
00095                 dfs (bb);
00096                 for (stmt_list_p q = b->stmts().begin(); 
00097                         q!=b->stmts().end(); ) {
00098                         if (!marked[*q]) {
00099                                 //output_context oc(cout);
00100                                 //cout <<"erasing following node " << endl;
00101                                 //(*q)->output(oc, NULL);
00102                                 //cout <<endl;
00103                                 q = b->stmts().erase (q);
00104                         } else {
00105                                 assert ((*q)->typ() == Block);
00106                                 fixup_preds ((basicblockNode *) *q);
00107                                 q++;
00108                         }
00109                 }
00110         }
00111 };
00112 
00113 void cfg_changer::generate_cfg(unitNode * the_unit) {
00114   Dismantle::dismantle(the_unit);
00115 
00116   cfg_changer cfgc;
00117   the_unit->change(cfgc);
00118 
00119   unreachableCodeRemover urcrm;
00120   the_unit->walk(urcrm);
00121 }
00122 
00123 Node * cfg_changer::at_proc (procNode *p, Order) {
00124         blockNode *b = p->body();
00125         bool unreachable = false;
00126 
00127         // place stmts in here to grow a basic block
00128 
00129         basicblockNode *bb = new basicblockNode (NULL, NULL);
00130 
00131         // for comments, we'll number the basic blocks
00132 
00133         int block_id = 1;
00134 
00135         // remember which block has which id
00136 
00137         map <basicblockNode *, int> id_map;
00138 
00139         // map from (goto) label strings to the block nodes
00140         // where they are defined.
00141 
00142         map <string, basicblockNode *> goto_label_map;
00143         basicblock_list_p q;
00144 
00145         // separate stmts into basic blocks
00146 
00147 #define EMIT_BB() { \
00148         if (bb->stmts().size()) basic_blocks.push_back (bb); \
00149                 bb = new basicblockNode (NULL, NULL); }
00150 
00151         basicblock_list basic_blocks;
00152 
00153         // -- Special case: If the first basic block starts with a label,
00154         // then we need a dummy "entry" basic block. Otherwise, this first
00155         // basic block will appear to have only one predecessor: the back
00156         // edge. That will confuse the SSA algorithm.
00157 
00158         if (b->stmts().front()->typ() == Label) {
00159           bb->stmts().push_back(new exprstmtNode((exprNode *)0));
00160           EMIT_BB();
00161         }
00162 
00163         for (stmt_list_p t=b->stmts().begin(); t!=b->stmts().end(); t++) {
00164                 stmtNode *s = *t;
00165 
00166                 // if we come upon a label, it needs to go into a new
00167                 // basic block
00168 
00169                 if (s->typ() == Label) {
00170                         EMIT_BB();
00171                         unreachable = false;
00172                 }
00173 
00174                 // stick the current statement into the current basic block
00175 
00176                 //if (!unreachable)
00177                         bb->stmts().push_back (s);
00178 
00179                 // if we come upon if, goto, or return, this is the end
00180                 // of this basic block
00181 
00182                 if (s->typ() == If || s->typ() == Condition) {
00183                         stmt_list_p q = t;
00184                         q++;
00185                         if (q != b->stmts().end() && (*q)->typ() == Goto) {
00186                                 t++;
00187                                 s = *t;
00188                                 bb->stmts().push_back (s);
00189                                 unreachable = true;
00190                         }
00191                         EMIT_BB();
00192                 } else  if (s->typ() == Goto 
00193                         || s->typ() == Return) {
00194                         EMIT_BB();
00195                         if (s->typ() == Goto) unreachable = true;
00196                 }
00197         }
00198 
00199         // emit any stmts not yet emitted (this shouldn't be necessary,
00200         // since a return should end the function, but better safe than
00201         // sorry).
00202 
00203         EMIT_BB();
00204 
00205         // place blocks back into function body, numbering them with
00206         // unique (to this procedure) ids
00207 
00208         b->stmts().clear();
00209         for (q=basic_blocks.begin(); 
00210                 q!=basic_blocks.end(); q++) {
00211                 id_map[*q] = block_id++;
00212                 b->stmts().push_back (*q);
00213         }
00214 
00215         // find preds and succs from if's that fall through
00216 
00217         for (q=basic_blocks.begin(); 
00218                 q!=basic_blocks.end(); q++) {
00219 
00220                 // if the last stmt in bb *q (get it?  BBQ?)
00221                 // isn't an unconditional jump, then the next bb is 
00222                 // a successor
00223 
00224                 stmtNode *r = (*q)->stmts().back();
00225                 if (r->typ() != Goto && r->typ() != Return) {
00226                         basicblock_list_p s = q;
00227                         s++;
00228                         //Want to add labels and gotos to all fall-through
00229                         //blocks
00230                         if (s != basic_blocks.end()) {
00231                                 (*s)->preds().push_front (*q);
00232                                 (*q)->succs().push_front (*s);
00233                                 if((*s)->stmts().front()->typ() != Label)
00234                                 {
00235                                    //create label
00236                                    labelNode * newLabel = 
00237                                        DismantleUtil::new_label((*s)->coord());
00238                                    //create goto
00239                                    gotoNode * newGoto = new gotoNode(newLabel);
00240                                  
00241                                    //put in respective places
00242                                    (*s)->stmts().push_front(newLabel);
00243                                    (*q)->stmts().push_back(newGoto);
00244                                 }
00245                                 else if((*q)->stmts().back()->typ() != Goto)
00246                                 {
00247                                    labelNode * label = (labelNode *)
00248                                                        (*s)->stmts().front();
00249                                    //create goto to that label
00250                                    gotoNode * newGoto = new gotoNode(label);
00251                                    //push on back
00252                                    (*q)->stmts().push_back(newGoto);
00253                                 }
00254                         }
00255                 }
00256         }
00257 
00258         // find preds and succs from goto's and labels
00259         // first, make a map from labels to basic blocks
00260 
00261         for (q=basic_blocks.begin(); 
00262                 q!=basic_blocks.end(); q++) {
00263                 stmtNode *r = (*q)->stmts().front();
00264                 if (r->typ() == Label) 
00265                         goto_label_map[((labelNode *)r)->name()] = *q;
00266         }
00267 
00268         // now, for any [if] goto stmt, the containing basic block
00269         // is a pred of the labeled stmt, and the labeled stmt
00270         // is a succ of the basic block
00271 
00272         for (q=basic_blocks.begin(); 
00273                 q!=basic_blocks.end(); q++) {
00274 
00275                 // go through all the stmts in the block looking
00276                 // for ifs and gotos.  Note: they should only appear
00277                 // around the end, but this makes it more general
00278                 // in case we want to start messing with "superblocks."
00279 
00280                 for (stmt_list_p s=(*q)->stmts().begin();
00281                         s != (*q)->stmts().end(); s++) {
00282                         stmtNode *r = *s;
00283                         bool is_if = false;
00284 
00285                         // if we find an 'if', get a pointer to the
00286                         // corresponding 'goto'.
00287 
00288                         if (r->typ() == If) {
00289                                 is_if = true;
00290                                 ifNode *g = (ifNode *) r;
00291                                 blockNode *b = (blockNode *) g->stmt();
00292                                 r = b->stmts().front();
00293         
00294                                 // dismantled code should only have if/goto
00295 
00296                                 assert (r->typ() == Goto);
00297                         }
00298                         if (r->typ() == Condition) {
00299                                 is_if = true;
00300                         }
00301                         if (r->typ() == Goto || r->typ() == Condition) {
00302                                 procNode * proc = p;
00303                                 basicblockNode *p = 
00304                                         goto_label_map[((gotoNode *)r)->name()];
00305         
00306                                 // the label should be defined in the function
00307                                 if (!p) {
00308                                   cerr << "No label for goto " << ((gotoNode *)r)->name() << endl;
00309                                   cerr << "  at " << proc->decl()->name() << endl;
00310                                 }
00311         
00312                                 assert (p);
00313 
00314                                 // if this came from an if, make
00315                                 // it the second succ,
00316                                 // else make it the first
00317 
00318                                 if (is_if)
00319                                         (*q)->succs().push_back (p);
00320                                 else
00321                                         (*q)->succs().push_front (p);
00322                                 p->preds().push_back (*q);
00323                         }
00324                 }
00325         }
00326 
00327         // uniquify each list of preds and succs
00328 
00329         for (q=basic_blocks.begin(); 
00330                 q!=basic_blocks.end(); q++) {
00331                 (*q)->succs().sort();
00332                 (*q)->succs().unique();
00333                 (*q)->preds().sort();
00334                 (*q)->preds().unique();
00335         }
00336 
00337         // insert comments into each basic block about its preds and succs
00338 
00339         for (q=basic_blocks.begin(); 
00340                 q!=basic_blocks.end(); q++) {
00341                 string s("");
00342                 char c[100];
00343                 sprintf (c, "%d", id_map[*q]);
00344                 s += "# ";
00345                 s += c;
00346                 s += ": preds( ";
00347                 (*q)->comment() = s;
00348                 for (basicblock_list_p l=(*q)->preds().begin();
00349                         l!=(*q)->preds().end(); l++) {
00350                         sprintf (c, "%d", id_map[*l]);
00351                         s += c;
00352                         s += " ";
00353                 }
00354                 s += ") succs( ";
00355                 for (basicblock_list_p l=(*q)->succs().begin();
00356                         l!=(*q)->succs().end(); l++) {
00357                         sprintf (c, "%d", id_map[*l]);
00358                         s += c;
00359                         s += " ";
00360                 }
00361                 s += ")";
00362                 (*q)->comment() = s;
00363         }
00364         return p;
00365 }

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