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  

loops.cc

Go to the documentation of this file.
00001 // $Id: loops.cc,v 1.7 2003/08/07 23:14:18 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 #include <set>
00039 #include "c_breeze.h"
00040 #include "dominators.h"
00041 #include "loops.h"
00042 
00043 // ----------------------------------------------------------------------
00044 //   Loop Tree Node
00045 // ----------------------------------------------------------------------
00046 
00047 loopTreeNode::loopTreeNode(LoopKind kind, basicblockNode * header)
00048   : _kind(kind),
00049     _header(header),
00050     _preheader(0),
00051     _parentLoop(0),
00052     _nestedLoops(),
00053     _blocks()
00054 {
00055   _blocks.insert(header);
00056 }
00057 
00058 void loopTreeNode::output(output_context & ct, Node * parent)
00059 {
00060    output_stmt(ct, parent);
00061 }
00062 
00063 void loopTreeNode::output_stmt(output_context & ct, Node * parent)
00064 {
00065 
00066    cout << "LoopTreeNode header: " << endl;
00067    _header->output(ct, NULL);
00068 
00069 }
00070 
00071 
00072 void loopTreeNode::report()
00073 {
00074   switch (kind()) {
00075   case SingleEntry:
00076     cout << "Single entry: ";
00077     break;
00078   case MultipleEntry:
00079     cout << "Multiple entry: ";
00080     break;
00081   case Top:
00082     cout << "(Top): ";
00083     break;
00084   default:
00085     cout << "(ERROR): ";
00086     break;
00087   }
00088 
00089   cout << "Depth = " << depth() << ", ";
00090 
00091   cout << "Header is #" << header()->dfn();
00092   cout << ", blocks: ";
00093 
00094   for (basicblock_set_p p = blocks().begin();
00095        p != blocks().end();
00096        ++p)
00097     cout << "#" << (*p)->dfn() << " ";
00098 
00099   cout << endl;
00100 }
00101 
00102 // ----------------------------------------------------------------------
00103 //   Loop Tree
00104 // ----------------------------------------------------------------------
00105 
00106 loopTree::loopTree(procNode * procedure)
00107   : _procedure(procedure),
00108     _top(0),
00109     _loops(),
00110     _containedIn(),
00111     _backEdges(),
00112     _forwardEdges(),
00113     _crossEdges()
00114 {
00115   // -- Perform a depth-first search, classifying edges and building a
00116   // post-order list of basic blocks.
00117 
00118   basicblock_list post_order;
00119   classifyEdges(post_order);
00120 
00121   // -- Build the loop tree: visit the nodes in post-order (basically,
00122   // bottom up) finding loops and assembling them into the loop tree.
00123 
00124   basicblock_set_map generators_map;
00125 
00126   for (basicblock_list_p p = post_order.begin();
00127        p != post_order.end();
00128        ++p)
00129     {
00130       basicblockNode * cur = *p;
00131 
00132       // -- If the current block has generators, then it represents a
00133       // multiple entry loop that we previously found. The current node has
00134       // been chosen to represent the loop because it is the nearest node
00135       // that dominates all nodes in the loop.
00136 
00137       if ( ! generators_map[cur].empty() )
00138         findBody(cur, generators_map[cur], loopTreeNode::MultipleEntry);
00139 
00140       // -- Check to see if the current node is the entry point for a loop.
00141 
00142       findLoop(cur, generators_map);
00143     }
00144 
00145   // -- Create a fake top node for the tree
00146 
00147   basicblock_set just_exit;
00148   just_exit.insert(procedure->exit());
00149 
00150   findBody(procedure->entry(), just_exit, loopTreeNode::Top);
00151 
00152   // -- Set the depths of each loop tree node
00153 
00154   setDepths(_top, 0);
00155 }
00156 
00157 loopTree::~loopTree()
00158 {
00159   // -- Delete all the loop tree nodes
00160 
00161   for (loop_list_p p = _loops.begin();
00162        p != _loops.end();
00163        ++p)
00164     delete *p;
00165 }
00166 
00167 loopTreeNode * loopTree::whichLoop(basicblockNode * block)
00168 {
00169   blockloop_map_p p = _containedIn.find(block);
00170   if (p != _containedIn.end())
00171     return (*p).second;
00172   else
00173     return 0;
00174 }
00175 
00176 void loopTree::findLoop(basicblockNode * candidate,
00177                         basicblock_set_map & generators_map)
00178 {
00179   // -- A basic block is the entry to a loop if it has back-edges.
00180 
00181   edge_map_p p = _backEdges.find(candidate);
00182 
00183   if (p != _backEdges.end()) {
00184 
00185     // -- This is a loop, collect the loop information.
00186 
00187     // We collect the predecessors of this basic block that are in the loop
00188     // (the heads of the back-edges), which we call "generators". These are
00189     // used later to generate the loop body. We also compute the "header",
00190     // which is the common dominator for all nodes in the loop.
00191 
00192     basicblock_set & predecessors = (*p).second;
00193 
00194     // -- Start by assuming the header is the candidate itself
00195 
00196     basicblockNode * header = candidate;
00197 
00198     // -- Collect the generators into this set
00199 
00200     basicblock_set generators;
00201 
00202     // -- For each predecessor....
00203 
00204     for (basicblock_set_p q = predecessors.begin();
00205          q != predecessors.end();
00206          ++q)
00207       {
00208         basicblockNode * pred = *q;
00209 
00210         // -- Add it into the common dominator 
00211 
00212         header = commonDominator(header, pred);
00213 
00214         // -- Add it to the generators set
00215 
00216         if (pred != candidate)
00217           generators.insert(pred);
00218       }
00219 
00220     // -- If the common dominator is the same as the candidate loop head,
00221     // then we have a single-entry loop. The reason is that if the
00222     // candidate node doesn't dominate all the nodes in the loop, then
00223     // there must be another entry point.
00224 
00225     if (header == candidate) {
00226 
00227       // -- Single-entry loop; find the body and create a loopTree entry
00228       // right now
00229 
00230       findBody(candidate, generators, loopTreeNode::SingleEntry);
00231     }
00232     else {
00233 
00234       // -- For multiple entry loops, we will construct the body later when
00235       // we encounter the header in the post-order traversal. We store the
00236       // generators in a map until then.
00237 
00238       generators_map[header].insert(generators.begin(), generators.end());
00239     }
00240   }
00241 }
00242 
00243 void loopTree::findBody(basicblockNode * head,
00244                         basicblock_set & generators,
00245                         loopTreeNode::LoopKind kind)
00246 {
00247   // -- Collect the basic blocks in this loop
00248 
00249   basicblock_set loop_nodes;
00250 
00251   // -- Maintain the queue of unprocessed nodes
00252 
00253   basicblock_list loop_queue;
00254 
00255   // -- First, initialize the queue and loop nodes with the generator
00256   // set. We skip any basic blocks that are already members of some other
00257   // loop.
00258 
00259   for (basicblock_set_p p = generators.begin();
00260        p != generators.end();
00261        ++p)
00262     {
00263       basicblockNode * generator = *p;
00264 
00265       loopTreeNode * loop = whichLoop(generator);
00266       if (! loop) {
00267         loop_nodes.insert(generator);
00268         loop_queue.push_back(generator);
00269       }
00270     }
00271 
00272   // -- Worklist algorithm: use the queue to add nodes to the loop by
00273   // moving backwards from the generators until we find the header.
00274 
00275   while ( ! loop_queue.empty()) {
00276 
00277     basicblockNode * cur = loop_queue.front();
00278     loop_queue.pop_front();
00279 
00280     // -- For each predecessor
00281 
00282     for (basicblock_list_p q = cur->preds().begin();
00283          q != cur->preds().end();
00284          ++q)
00285       {
00286         basicblockNode * pred = *q;
00287 
00288         // -- If we haven't reached the head and we haven't seen this node
00289         // yet, then put it on the queue.
00290 
00291         if ((pred != head) &&
00292             (loop_nodes.find(pred) == loop_nodes.end())) {
00293           loop_nodes.insert(pred);
00294           loop_queue.push_back(pred);
00295         }
00296       }
00297   }
00298 
00299   // -- Create a new loopTreeNode with the basic information gathered. The
00300   // rest of the code populates the object.
00301 
00302   loopTreeNode * loop = new loopTreeNode(kind, head);
00303 
00304   _containedIn[head] = loop;
00305 
00306   _loops.push_front(loop);
00307 
00308   // -- Visit the blocks in the loop, determining which ones are owned by
00309   // this loop. As a consequence, we also determine the nested loops.
00310 
00311   for (basicblock_set_p w = loop_nodes.begin();
00312        w != loop_nodes.end();
00313        ++w)
00314     {
00315       basicblockNode * block = *w;
00316 
00317       // -- Check to see if this block is already "owned"
00318 
00319       loopTreeNode * nested_loop = whichLoop(block);
00320       if (nested_loop) {
00321 
00322         // -- It is, add it's nearest ancestor to the list of nested loops
00323 
00324         loopTreeNode * ancestor = loopAncestor(nested_loop);
00325 
00326         if (ancestor != loop) {
00327           loop->addNestedLoop(ancestor);
00328           ancestor->parentLoop(loop);
00329         }
00330       }
00331       else {
00332 
00333         // -- Not owned, record it as owned by this loop
00334 
00335         _containedIn[block] = loop;
00336 
00337         // -- Add the block to the loop
00338 
00339         loop->addBlock(block);
00340       }
00341     }
00342 
00343   // -- Put some information in the comment
00344 
00345   if (kind != loopTreeNode::Top) {
00346 
00347     ostringstream comment;
00348 
00349     comment << endl;
00350     switch (kind) {
00351     case loopTreeNode::SingleEntry:
00352       comment << "    Single entry loop: ";
00353       break;
00354     case loopTreeNode::MultipleEntry:
00355       comment << "    Multiple entry loop: ";
00356       break;
00357     default:
00358       comment << "    (ERROR): ";
00359       break;
00360     }
00361 
00362     for (basicblock_set_p p = loop->blocks().begin();
00363          p != loop->blocks().end();
00364          ++p)
00365       {
00366         basicblockNode * bb = *p;
00367         comment << " #" << _preOrder[bb] << " ";
00368       }
00369 
00370     head->comment() += comment.str();
00371   }
00372 
00373   // -- Finally, if the loop kind is "Top", record it as the top of the
00374   // tree.
00375 
00376   if (kind == loopTreeNode::Top)
00377     _top = loop;
00378 }
00379 
00380 basicblockNode * loopTree::commonDominator(basicblockNode * first,
00381                                            basicblockNode * second)
00382 {
00383   // -- Simple algorithm: go up one IDOM chain until we find a node that
00384   // dominates the other
00385 
00386   basicblockNode * cur = first;
00387 
00388   while ( cur && ( ! Dominators::dominates(cur, second)))
00389     cur = cur->parent();
00390 
00391   // -- Sanity check (the entry node should dominate everything)
00392 
00393   if ( ! cur )
00394     cerr << "ERROR: Entry node does not dominate the rest of the basic blocks" << endl;
00395 
00396   return cur;
00397 }
00398 
00399 loopTreeNode * loopTree::loopAncestor(loopTreeNode * loop)
00400 {
00401   loopTreeNode * cur = loop;
00402 
00403   while (cur->parentLoop())
00404     cur = cur->parentLoop();
00405 
00406   return cur;
00407 }
00408 
00409 void loopTree::classifyEdges(basicblock_list & post_order)
00410 {
00411   // -- Make sure all the orderings and lists are clear (so that we can
00412   // call this routine more than once)
00413 
00414   _backEdges.clear();
00415   _forwardEdges.clear();
00416   _crossEdges.clear();
00417   _preOrder.clear();
00418   _rpostOrder.clear();
00419 
00420   // -- Initialize all the numberings to -1, which signifies "unprocessed
00421   // block"
00422 
00423   stmt_list & body = _procedure->body()->stmts();
00424 
00425   int pre_order_number = 0;
00426   int rpost_order_number = body.size() - 1;
00427 
00428   for (stmt_list_p x = body.begin();
00429        x != body.end();
00430        ++x)
00431     {
00432       basicblockNode * cur = (basicblockNode *) *x;
00433       _preOrder[cur] = -1;
00434       _rpostOrder[cur] = -1;
00435     }
00436 
00437   // -- Run the depth-first search
00438 
00439   depthFirstSearch(_procedure->entry(), post_order,
00440                    pre_order_number, rpost_order_number);
00441 }
00442 
00443 void loopTree::depthFirstSearch(basicblockNode * cur,
00444                                 basicblock_list & post_order,
00445                                 int & pre_order_number,
00446                                 int & rpost_order_number)
00447 {
00448   // -- Build a comment
00449 
00450   ostringstream comment;
00451 
00452   // -- Set the pre-order number
00453 
00454   _preOrder[cur] = pre_order_number;
00455   comment << " BB #" << pre_order_number;
00456   pre_order_number++;
00457 
00458   // -- For each successor, classify the edge and call recursively if
00459   // necessary.
00460 
00461   comment << " : Successors: ";
00462 
00463   for (basicblock_list_p p = cur->succs().begin();
00464        p != cur->succs().end();
00465        ++p)
00466     {
00467       basicblockNode * successor = *p;
00468       EdgeKind kind;
00469 
00470       if (_preOrder[successor] == -1) {
00471 
00472         // -- Unvisited child: this is a tree edge
00473 
00474         kind = TreeEdge;
00475 
00476         _treeEdges[cur].insert(successor);
00477 
00478         depthFirstSearch(successor, post_order,
00479                          pre_order_number, rpost_order_number);
00480       }
00481       else if (_rpostOrder[successor] == -1) {
00482 
00483         // -- Successor is an ancestor: this is a back-edge
00484 
00485         kind = BackEdge;
00486 
00487         _backEdges[successor].insert(cur);
00488       }
00489       else if (_preOrder[cur] < _preOrder[successor]) {
00490 
00491         // -- Successor is a descendant: this is a forward edge
00492 
00493         kind = ForwardEdge;
00494 
00495         _forwardEdges[cur].insert(successor);
00496       }
00497       else {
00498 
00499         // -- Any other edge is a cross edge
00500 
00501         kind = CrossEdge;
00502 
00503         _crossEdges[cur].insert(successor);
00504       }
00505 
00506       comment << " #" << _preOrder[successor] << " ";
00507       switch (kind) {
00508       case TreeEdge: comment << "(Tree)";
00509         break;
00510       case BackEdge: comment << "(Back)";
00511         break;
00512       case ForwardEdge: comment << "(Forward)";
00513         break;
00514       case CrossEdge: default: comment << "(Cross)";
00515         break;
00516       }
00517       comment << " ";
00518     }
00519 
00520   // -- Store comment
00521 
00522   cur->comment() = comment.str(); 
00523 
00524   // -- Store this node in the post-order
00525 
00526   post_order.push_back(cur);
00527 
00528   // -- Set the post-order number
00529 
00530   _rpostOrder[cur] = rpost_order_number;
00531   rpost_order_number--;
00532 }
00533 
00534 void loopTree::setDepths(loopTreeNode * cur, int depth)
00535 {
00536   // -- Set the current depth
00537 
00538   cur->depth(depth);
00539 
00540   // -- Visit the children
00541 
00542   for (loop_set_p q = cur->nestedLoops().begin();
00543        q != cur->nestedLoops().end();
00544        ++q)
00545     setDepths(*q, depth+1);
00546 }
00547 
00548 loopTree::EdgeKind loopTree::classifyEdge(basicblockNode * source,
00549                                           basicblockNode * target)
00550 {
00551   edge_map_p p;
00552 
00553   // -- Try the backedges first (NOTE: they are indexed by the target block).
00554 
00555   
00556   p = _backEdges.find(target);
00557   if (p != _backEdges.end()) {
00558     basicblock_set & edges = (*p).second;
00559     if (edges.find(source) != edges.end())
00560       return BackEdge;
00561   }
00562 
00563   // -- Try the forward edges
00564 
00565   p = _forwardEdges.find(source);
00566   if (p != _forwardEdges.end()) {
00567     basicblock_set & edges = (*p).second;
00568     if (edges.find(target) != edges.end())
00569       return ForwardEdge;
00570   }
00571 
00572   // -- Try the cross edges
00573 
00574   p = _crossEdges.find(source);
00575   if (p != _crossEdges.end()) {
00576     basicblock_set & edges = (*p).second;
00577     if (edges.find(target) != edges.end())
00578       return CrossEdge;
00579   }
00580 
00581   // -- If it's none of the above, then it's a tree edge
00582 
00583   return TreeEdge;
00584 }
00585 
00586 void loopTree::report()
00587 {
00588   cout << "Loop tree:" << endl;
00589 
00590   report(_top, 0);
00591 }
00592 
00593 
00594 void loopTree::report(loopTreeNode * cur, int level)
00595 {
00596   for (int i = 0; i < level*2; i++)
00597     cout << " ";
00598 
00599   cur->report();
00600 
00601   for (loop_set_p q = cur->nestedLoops().begin();
00602        q != cur->nestedLoops().end();
00603        ++q)
00604     report(*q, level+1);
00605 }
00606 

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