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  

lir_flow_walker.cc

Go to the documentation of this file.
00001 // $Id: lir_flow_walker.cc,v 1.9 2003/08/11 17:38:52 abrown Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2002 University of Texas at Austin
00008 // 
00009 //  Paul Arthur Navratil
00010 //  Charles Nevill
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 "c_breeze.h"
00039 #include "lir_flow_walker.h"
00040 #include "LIR.h"
00041 
00042 
00043 lir_flow_walker::lir_flow_walker ():
00044 Walker (Both, Subtree)
00045 {
00046 }
00047 
00048 lir_flow_walker::~lir_flow_walker ()
00049 {
00050 }
00051 
00052 void
00053 lir_flow_walker::build_lir_blocks (procNode * the_proc)
00054 {
00055   // the list of blocks we're building
00056   LirBlockList & blocks = the_proc->lir_blocks ();
00057   blocks.clear ();
00058 
00059   // a map from label name to the block which that lable heads
00060   typedef map < string, LirBlock * >HeaderMap;
00061   HeaderMap headerMap;
00062 
00063   // build the actual blocks
00064   int next = 1;
00065   const instruction_list & insts = the_proc->instructions ();
00066   instruction_list::const_iterator instIt = insts.begin ();
00067   LirBlock *block = new LirBlock (next++);
00068   bool nextNew = false;
00069   for (; instIt != insts.end (); ++instIt)
00070     {
00071       LirInst *inst = *instIt;
00072 
00073       // are we starting a new block? (happens at label and after
00074       // jump/branch)
00075       mnemonic mn = inst->instruction;
00076       if (mn == mn_Label || nextNew)
00077         {
00078           // add the old block to the list and make a new one
00079           if (block->insts ().size () > 0)
00080             {
00081               blocks.push_back (block);
00082               LirBlock *tempblock = new LirBlock (next++);
00083               block->_next = tempblock;
00084               block = tempblock;
00085             }
00086 
00087           // remember that this label heads this block
00088           headerMap[inst->target] = block;
00089         }
00090 
00091       // reset this
00092       nextNew = false;
00093 
00094       // which instruction is this?
00095       switch (mn)
00096         {
00097         case mn_BranchEQ:
00098         case mn_BranchNE:
00099         case mn_BranchLT:
00100         case mn_BranchLE:
00101         case mn_BranchGT:
00102         case mn_BranchGE:
00103         case mn_Jmp:
00104 
00105           // a new block next time around
00106           nextNew = true;
00107           break;
00108 
00109         default:
00110 
00111           // nothing special
00112           break;
00113         }
00114 
00115       // add this instruction to the block
00116       block->add_inst (inst);
00117     }
00118 
00119   // add the last one
00120   if (block->insts ().size () > 0)
00121     blocks.push_back (block);
00122 
00123   // build succs/preds arrays
00124   LirBlock *s1, *s2;
00125   HeaderMap::iterator findIt;
00126   LirBlockList_p b;
00127   for (b = blocks.begin (); b != blocks.end (); ++b)
00128     {
00129       LirBlock *block = *b;
00130 
00131       // assume no successors
00132       s1 = NULL;
00133       s2 = NULL;
00134 
00135       // get last instruction in this block
00136       LirInst *last = block->insts ().back ();
00137       switch (last->instruction)
00138         {
00139         case mn_Jmp:
00140 
00141           // find jump target
00142           s1 = headerMap[last->target];
00143           assert (s1);
00144           break;
00145 
00146         case mn_BranchEQ:
00147         case mn_BranchNE:
00148         case mn_BranchLT:
00149         case mn_BranchLE:
00150         case mn_BranchGT:
00151         case mn_BranchGE:
00152 
00153           // find branch target and fall-through case
00154           s1 = headerMap[last->target];
00155           assert (s1);
00156           s2 = block->_next;
00157           break;
00158 
00159         case mn_Return:
00160 
00161           // no successors
00162           break;
00163 
00164         default:
00165 
00166           // only target is successor block
00167           s1 = block->_next;
00168           break;
00169         }
00170 
00171       // setup linkages between target and source
00172       if (s1)
00173         {
00174           block->_succs.insert (s1);
00175           s1->_preds.insert (block);
00176         }
00177       if (s2)
00178         {
00179           block->_succs.insert (s2);
00180           s2->_preds.insert (block);
00181         }
00182     }
00183 
00184 }
00185 
00186 void
00187 lir_flow_walker::get_block_dfo (LirBlock * block, LirBlockList & blocks)
00188 {
00189   // skip if invalid block or already visited
00190   if (!block || block->_visited)
00191     return;
00192 
00193   // we have visted this now
00194   block->_visited = true;
00195 
00196   // process all successors first
00197   LirBlockSet_p it;
00198   for (it = block->_succs.begin (); it != block->_succs.end (); ++it)
00199     get_block_dfo (*it, blocks);
00200 
00201   // finally put us into the ordering
00202   blocks.push_back (block);
00203 }
00204 
00205 void
00206 lir_flow_walker::find_block_doms (procNode * the_proc)
00207 {
00208   LirBlockList & blocks = the_proc->lir_blocks ();
00209   LirBlockList_p it;
00210 
00211   // 
00212   // this is basically a transcription of the code from Muchnick ACDI,
00213   // page 182, figure 7.14
00214   // 
00215 
00216   // any to do at all?
00217   if (blocks.size () < 1)
00218     return;
00219 
00220   // generate a depth-first ordering on the blocks
00221   LirBlockList dfoBlocks;
00222   LirBlock *root = *(blocks.begin ());
00223   root->reset_visited ();
00224   get_block_dfo (root, dfoBlocks);
00225 
00226   // build set of all blocks
00227   LirBlockSet allBlocks;
00228   it = dfoBlocks.begin ();
00229   while (it != dfoBlocks.end ())
00230     allBlocks.insert (*(it++));
00231 
00232   // set all blocks dominated by everything to start with
00233   it = blocks.begin ();
00234   while (it != blocks.end ())
00235     (*it++)->_doms = allBlocks;
00236 
00237   // root dominates itself only
00238   root->_doms.clear ();
00239   root->_doms.insert (root);
00240 
00241   // take root out of allBlocks to get depth-first ordered list minus root
00242   LirBlockSet allNoRoot = allBlocks - root;
00243 
00244   // figure out dominance relationship
00245   bool changed;
00246   LirBlockSet t, d;
00247   do
00248     {
00249       // no change yet
00250       changed = false;
00251 
00252       // process all except root, in depth-first order
00253       LirBlockSet_p itn;
00254       for (itn = allNoRoot.begin (); itn != allNoRoot.end (); ++itn)
00255         {
00256           LirBlock *n = *itn;
00257 
00258           // init this set to all blocks
00259           t = allBlocks;
00260 
00261           // modify according to this guy's predecessors
00262           LirBlockSet_p pred;
00263           for (pred = n->_preds.begin (); pred != n->_preds.end (); ++pred)
00264             t &= (*pred)->_doms;
00265 
00266           // did the set change?
00267           d = t | n;
00268           if (d != n->_doms)
00269             {
00270               n->_doms = d;
00271               changed = true;
00272             }
00273         }
00274     }
00275   while (changed);
00276 }
00277 
00278 void
00279 lir_flow_walker::find_loops (procNode * proc, bool need_recompute_flow,
00280                              vector < LirBlockSet > &loops)
00281 {
00282   // do we have to recompute things?
00283   if (need_recompute_flow)
00284     {
00285       build_lir_blocks (proc);
00286       find_block_doms (proc);
00287       debug_print_block_info (proc);
00288     }
00289 
00290   // reset loop depth and generate list of back edges
00291   edge_list backedges;
00292   LirBlockList & blocks = proc->lir_blocks ();
00293   LirBlockList_p bl = blocks.begin ();
00294   for (; bl != blocks.end (); ++bl)
00295     {
00296       LirBlock *block = *bl;
00297 
00298       // reset depth to zero
00299       block->_depth = 0;
00300 
00301       // look at successors other than next sequential instruction
00302       LirBlockSet & succs = block->_succs;
00303       LirBlockSet::iterator suc = succs.begin ();
00304       for (; suc != succs.end (); ++suc)
00305         {
00306           LirBlock *succ = *suc;
00307 
00308           // ignore immediate successor
00309           if (succ == block->_next)
00310             continue;
00311 
00312           // does successor dominate us?
00313           if (block->_doms.find (succ) != block->_doms.end ())
00314             {
00315               // add a backedge
00316               edge e = { block, succ };
00317               backedges.push_back (e);
00318             }
00319         }
00320     }
00321 
00322   // use muchnick's algorithm from ACDI, figure 7.21 to find loops
00323   loops.clear ();
00324   edge_list_p edg = backedges.begin ();
00325   LirBlock *p, *q;
00326   for (; edg != backedges.end (); ++edg)
00327     {
00328       LirBlockList stack;
00329 
00330       edge & e = *edg;
00331       LirBlock *m = e.source, *n = e.target;
00332 
00333       // add a new loop
00334       int sz = loops.size () + 1;
00335       loops.resize (sz);
00336       LirBlockSet & loop = loops[sz - 1];
00337       loop.insert (m);
00338       loop.insert (n);
00339 
00340       // setup stack and run till we're done
00341       if (m != n)
00342         stack.push_back (m);
00343       while (stack.size () > 0)
00344         {
00345           // get end of stack
00346           p = stack.back ();
00347           stack.pop_back ();
00348 
00349           // iterate over preds of p
00350           LirBlockSet_p pr = p->_preds.begin ();
00351           for (; pr != p->_preds.end (); ++pr)
00352             {
00353               q = *pr;
00354               if (loop.find (q) == loop.end ())
00355                 {
00356                   loop.insert (q);
00357                   stack.push_back (q);
00358                 }
00359             }
00360         }
00361     }
00362 
00363   // setup loop depth of blocks
00364   vector < LirBlockSet >::iterator lp = loops.begin ();
00365   for (; lp != loops.end (); ++lp)
00366     {
00367       // increment depth of each block
00368       LirBlockSet & loop = *lp;
00369       LirBlockSet_p bl = loop.begin ();
00370       for (; bl != loop.end (); ++bl)
00371         (*bl)->_depth++;
00372     }
00373 
00374 }
00375 
00376 void
00377 lir_flow_walker::at_proc (procNode * the_proc, Order ord)
00378 {
00379   if (ord != Preorder)
00380     return;
00381 
00382   // build basic blocks and find dominators
00383   build_lir_blocks (the_proc);
00384   find_block_doms (the_proc);
00385 
00386   // print this out
00387   debug_print_block_info (the_proc);
00388 }
00389 
00390 
00391 
00392 void
00393 lir_flow_walker::computeRegisterLiveness (instruction_list & insts,
00394                                           inst_to_reg_id_map & liveRegs)
00395 {
00396   // generate flow info for instructions
00397   getInstructionFlowInfo (insts);
00398 
00399   // mark all not visited, and clear set of live regs for each instruction
00400   instruction_list_p it = insts.begin ();
00401   for (; it != insts.end (); ++it)
00402     {
00403       LirInst *inst = *it;
00404       inst->visited = false;
00405       liveRegs[inst].clear ();
00406     }
00407 
00408   // generate postorder ordering of instructions
00409   instruction_list rpo;
00410   getInstructionsPostorder (insts, insts.begin (), rpo);
00411 
00412   // for debugging - trace out instructions in postorder
00413   // change 0 to 1 to add this code
00414 #if 0
00415   {
00416     cout << "DEBUG:" << endl;
00417     cout << "Postorder:" << endl;
00418     instruction_list_p it = rpo.begin ();
00419     for (; it != rpo.end (); ++it)
00420       cout << **it << endl;
00421     cout << "END DEBUG" << endl;
00422   }
00423 #endif
00424 
00425   // do iterative dataflow analysis to find live registers at each
00426   // instruction
00427   instruction_list worklist = rpo;
00428   unsigned int idFp = CBZ::ArchInfo.get_reg_fp ()->_id;
00429   unsigned int idSp = CBZ::ArchInfo.get_reg_sp ()->_id;
00430   unsigned int idRvFixed = (unsigned int) -1;
00431   if (CBZ::ArchInfo.get_reg_retval_fixed ())
00432     idRvFixed = CBZ::ArchInfo.get_reg_retval_fixed ()->_id;
00433   unsigned int idRvFloat = (unsigned int) -1;
00434   if (CBZ::ArchInfo.get_reg_retval_float ())
00435     idRvFloat = CBZ::ArchInfo.get_reg_retval_float ()->_id;
00436   while (worklist.size () != 0)
00437     {
00438       // get front of worklist
00439       LirInst *inst = worklist.front ();
00440       worklist.pop_front ();
00441 
00442       // what is used by this?
00443       reg_id_set used;
00444       if (inst->has_opnd1 ())
00445         used.insert (inst->opnd1.num ());
00446       if (inst->has_opnd2 ())
00447         used.insert (inst->opnd2._reg.num ());
00448       if (inst->has_base ())
00449         used.insert (inst->memBase.num ());
00450       if (inst->has_offset ())
00451         used.insert (inst->memOffset._reg.num ());
00452 
00453       // compute our successors' info
00454       reg_id_set succLive;
00455       instruction_set_p sit = inst->succs.begin ();
00456       for (; sit != inst->succs.end (); ++sit)
00457         succLive |= liveRegs[*sit];
00458 
00459       // what do we generate/kill?
00460       reg_id_set killRegs;
00461       if (inst->has_dest ())
00462         {
00463           // we kill destination register
00464           killRegs |= inst->dest.num ();
00465         }
00466 
00467       // new liveness for us
00468       reg_id_set live = used | (succLive - killRegs);
00469 
00470       // we never care about liveness for stack ptr, frame ptr, or return
00471       // value registers
00472       // because these registers are never saved by us.
00473       live -= idFp;
00474       live -= idSp;
00475       live -= idRvFixed;
00476       live -= idRvFloat;
00477 
00478       // changed?
00479       if (liveRegs[inst] != live)
00480         {
00481           // new liveness for us
00482           liveRegs[inst] = live;
00483 
00484           // our predecessors have changed
00485           instruction_set_p pit = inst->preds.begin ();
00486           for (; pit != inst->preds.end (); ++pit)
00487             if (!cbz_util::list_find (worklist, *pit))
00488               worklist.push_back (*pit);
00489         }
00490     }
00491 }
00492 
00493 void
00494 lir_flow_walker::getInstructionsPostorder (instruction_list & insts,
00495                                            instruction_list_p it,
00496                                            instruction_list & ordering)
00497 {
00498   LirInst *inst = *it;
00499 
00500   // already in list?
00501   if (inst->visited)
00502     return;
00503 
00504   // set visited
00505   inst->visited = true;
00506 
00507   // add all successors first
00508   switch (inst->instruction)
00509     {
00510     case mn_Return:
00511 
00512       // no successors
00513       break;
00514 
00515     case mn_Jmp:
00516 
00517       // just has the one target
00518       assert (inst->targetInst);
00519       if (!inst->targetInst->visited)
00520         getInstructionsPostorder (insts,
00521                                   findInstruction (insts, inst->targetInst),
00522                                   ordering);
00523       break;
00524 
00525     case mn_BranchEQ:
00526     case mn_BranchNE:
00527     case mn_BranchLT:
00528     case mn_BranchLE:
00529     case mn_BranchGT:
00530     case mn_BranchGE:
00531 
00532       // has a branch target
00533       assert (inst->targetInst);
00534       if (!inst->targetInst->visited)
00535         getInstructionsPostorder (insts,
00536                                   findInstruction (insts, inst->targetInst),
00537                                   ordering);
00538 
00539       // also has not-taken - fall through for this
00540 
00541     default:
00542 
00543       // add next instruction at least
00544       assert (it != insts.end ());
00545       instruction_list_p next = it;
00546       next++;
00547       getInstructionsPostorder (insts, next, ordering);
00548       break;
00549     }
00550 
00551   // add us to ordering
00552   ordering.push_back (inst);
00553 }
00554 
00555 void
00556 lir_flow_walker::getInstructionFlowInfo (instruction_list & insts)
00557 {
00558   instruction_list_p it;
00559 
00560   // make forward pass to setup list of branch targets
00561   typedef map < string, LirInst * >target_map;
00562   target_map targets;
00563   for (it = insts.begin (); it != insts.end (); ++it)
00564     {
00565       LirInst *inst = *it;
00566 
00567       // clear out successors/predecessors arrays
00568       inst->succs.clear ();
00569       inst->preds.clear ();
00570 
00571       // label?
00572       if (inst->instruction == mn_Label)
00573         targets[inst->target] = inst;
00574     }
00575 
00576   // setup successors/predecessors
00577   LirInst *s1, *s2;
00578   for (it = insts.begin (); it != insts.end (); ++it)
00579     {
00580       LirInst *inst = *it;
00581 
00582       // assume no successors
00583       s1 = NULL;
00584       s2 = NULL;
00585 
00586       switch (inst->instruction)
00587         {
00588         case mn_Return:
00589         case mn_EndProc:
00590 
00591           // no successors, pred is setup by previous instruction
00592           break;
00593 
00594         case mn_Jmp:
00595           {
00596             // just has the one successor
00597             inst->targetInst = targets[inst->target];
00598             assert (inst->targetInst);
00599             s1 = inst->targetInst;
00600             break;
00601           }
00602         case mn_BranchEQ:
00603         case mn_BranchNE:
00604         case mn_BranchLT:
00605         case mn_BranchLE:
00606         case mn_BranchGT:
00607         case mn_BranchGE:
00608           {
00609             // has a branch target
00610             inst->targetInst = targets[inst->target];
00611             assert (inst->targetInst);
00612             s2 = inst->targetInst;
00613 
00614             // also has not-taken - fall through for this
00615           }
00616         default:
00617 
00618           // next instruction is successor
00619           instruction_list_p next = it;
00620           ++next;
00621           assert (next != insts.end ());
00622           s1 = *next;
00623           break;
00624         }
00625 
00626       // setup linkages between target and source
00627       if (s1)
00628         {
00629           inst->succs.insert (s1);
00630           s1->preds.insert (inst);
00631         }
00632       if (s2)
00633         {
00634           inst->succs.insert (s2);
00635           s2->preds.insert (inst);
00636         }
00637     }
00638 }
00639 
00640 instruction_list_p
00641   lir_flow_walker::findInstruction (instruction_list & insts,
00642                                     const LirInst * inst)
00643 {
00644   instruction_list_p it = insts.begin ();
00645   for (; it != insts.end (); ++it)
00646     if (*it == inst)
00647       return it;
00648   return it;
00649 }
00650 
00651 void
00652 lir_flow_walker::debug_print_block_info (procNode * proc)
00653 {
00654 #if 0
00655   // print out info
00656   LirBlockList & blocks = proc->lir_blocks ();
00657   LirBlockList_p it = blocks.begin ();
00658   int inst = 0;
00659   while (it != blocks.end ())
00660     {
00661       printf ("\n");
00662       printf ("\n");
00663       printf ("block %d (instructions %d through %d) ",
00664               (*it)->_number, inst, inst + (*it)->insts ().size () - 1);
00665       printf ("\n");
00666       printf ("dominated by: ");
00667       LirBlockSet_p doms = (*it)->_doms.begin ();
00668       while (doms != (*it)->_doms.end ())
00669         printf ("%d ", (*doms++)->_number);
00670       printf ("\n");
00671       printf ("predecessors: ");
00672       LirBlockSet_p preds = (*it)->_preds.begin ();
00673       while (preds != (*it)->_preds.end ())
00674         printf ("%d ", (*preds++)->_number);
00675       printf ("\n");
00676       printf ("successors: ");
00677       LirBlockSet_p succs = (*it)->_succs.begin ();
00678       while (succs != (*it)->_succs.end ())
00679         printf ("%d ", (*succs++)->_number);
00680       printf ("\n");
00681       inst += (*it)->insts ().size ();
00682       it++;
00683     }
00684 #endif
00685 }

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