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  

dismantle-control.cc

Go to the documentation of this file.
00001 // $Id: dismantle-control.cc,v 1.7 2003/08/07 23:13:42 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 //  Adam Brown
00013 // 
00014 //  Permission is hereby granted, free of charge, to any person
00015 //  obtaining a copy of this software and associated documentation
00016 //  files (the "Software"), to deal in the Software without
00017 //  restriction, including without limitation the rights to use, copy,
00018 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00019 //  of the Software, and to permit persons to whom the Software is
00020 //  furnished to do so, subject to the following conditions:
00021 //  
00022 //  The above copyright notice and this permission notice shall be
00023 //  included in all copies or substantial portions of the Software.
00024 //  
00025 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00026 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00027 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00028 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00029 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00030 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00031 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00032 //  THE SOFTWARE.
00033 //
00034 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00035 //  Computer Science for inspiring parts of the C-Breeze design.
00036 //
00037 // ----------------------------------------------------------------------
00038 //
00039 // dismantle-control.cc
00040 //
00041 
00042 #include "c_breeze.h"
00043 #include "dismantle.h"
00044 #include "ref_clone_changer.h"
00045 #include "set_container_walker.h"
00046 
00047 ControlDismantle::ControlDismantle(void):
00048   Changer(Preorder, Subtree, false)
00049 {}
00050 
00051 Node * ControlDismantle::at_proc(procNode * the_proc, Order ord) {
00052   set_container_walker::fixup(the_proc);
00053 
00054   LoopDismantle ld;
00055   the_proc->change(ld);
00056 
00057   TernaryDismantle td;
00058   the_proc->change(td);
00059 
00060   SelectionDismantle sd;
00061   the_proc->change(sd);
00062 
00063   ReturnDismantle rd;
00064   the_proc->change(rd);
00065 
00066   return the_proc;
00067 }
00068 
00069 // This class changes the body of a loop so that every 'break' is replaced
00070 // with a 'goto break_label' and every 'continue' is replaced with a
00071 // 'goto continue_label'.  It assumes that the set_container_walker has
00072 // already been run on the AST.
00073 BreakContinueChanger::BreakContinueChanger(Node * top, labelNode * break_label,
00074                                            labelNode * continue_label, loopNode *new_container) :
00075   Changer(Preorder, Subtree, false),
00076   _top(top),
00077   _break_label(break_label),
00078   _continue_label(continue_label),
00079   _new_container(new_container)
00080 {}
00081 
00082 Node * BreakContinueChanger::at_break(breakNode * the_break, Order ord) {
00083   if ( the_break->container() == _top 
00084        && _break_label )
00085     return new gotoNode(_break_label, the_break->coord());
00086   if ( the_break->container() == _top && _new_container )
00087     the_break->container( _new_container );
00088   return the_break;
00089 }
00090 
00091 Node * BreakContinueChanger::at_continue(continueNode * the_continue, 
00092                                          Order ord) {
00093   if ( the_continue->container() == _top
00094        && _continue_label )
00095     return new gotoNode(_continue_label, the_continue->coord());
00096   if ( the_continue->container() == _top && _new_container )
00097     the_continue->container( _new_container );
00098   return the_continue;
00099 }
00100 
00101 LoopDismantle::LoopDismantle(void):
00102   Changer(Preorder, Subtree, false)
00103 {}
00104 
00105 Node * LoopDismantle::at_while(whileNode * the_while, Order ord) {
00106   // while ( cond ) { body; ...
00107   //                  break; ...
00108   //                  continue; }
00109   // =>
00110   // {
00111   //   __test: ;
00112   //   if ( ! cond ) goto __exit;
00113   //   body; ...
00114   //   goto __exit; ...
00115   //   goto __test;
00116   //   __exit: ;
00117   // }
00118 
00119   blockNode * new_block = new blockNode(NULL, NULL, the_while->coord());
00120   labelNode * test_label = 
00121     DismantleUtil::new_label(the_while->coord());
00122   labelNode * exit_label = 
00123     DismantleUtil::new_label(the_while->coord());
00124   gotoNode * goto_exit = new gotoNode(exit_label, the_while->coord());
00125   exprNode * not_cond = DismantleUtil::Not(the_while->cond());
00126   ifNode * test_cond = new ifNode(not_cond, goto_exit, NULL, 
00127                                   the_while->coord());
00128   gotoNode * goto_test = new gotoNode(test_label, the_while->coord());
00129 
00130   new_block->stmts().push_back(test_label);
00131   new_block->stmts().push_back(test_cond);
00132   // replace 'break' & 'continue' with goto_exit & goto_test (resp).
00133   BreakContinueChanger bcc(the_while, exit_label, test_label);
00134   new_block->stmts().push_back((stmtNode *) the_while->body()->change(bcc));
00135 
00136   new_block->stmts().push_back(goto_test);
00137   new_block->stmts().push_back(exit_label);
00138 
00139   return new_block;
00140 }
00141 
00142 Node * LoopDismantle::at_for(forNode * the_for, Order ord) {
00143   // for ( init; cond; next ) {
00144   //   body; ...
00145   //   break; ...
00146   //   continue; ...
00147   // }
00148   // =>
00149   // {
00150   //   init;
00151   //   while ( cond ) {
00152   //     body; ...
00153   //     break; ...
00154   //     goto __next;
00155   //     __next: ;
00156   //     next;
00157   //   }
00158   // }
00159 
00160   blockNode * new_block = new blockNode(NULL, NULL, the_for->coord());
00161   exprstmtNode * init = new exprstmtNode(the_for->init());
00162   exprNode * while_cond = (the_for->cond()) ? the_for->cond() :
00163     new constNode(constant(1), "1", the_for->coord());
00164 
00165   blockNode * while_body = new blockNode(NULL, NULL, the_for->coord());
00166   whileNode * while_loop = new whileNode(while_cond, while_body,
00167                                          the_for->coord());
00168 
00169   // we only need to create the __next: label if the next portion of the
00170   // for loop is present.  otherwise, we let the while loop update any
00171   // continue statements.
00172   if ( the_for->next() ) {
00173     labelNode * next_label = DismantleUtil::new_label(the_for->coord());
00174     exprstmtNode * next_stmt = new exprstmtNode(the_for->next());
00175 
00176     // replace 'continue' with "goto next_label"
00177     BreakContinueChanger bcc(the_for, NULL, next_label, while_loop);
00178     while_body->stmts().push_back((stmtNode *) the_for->body()->change(bcc));
00179     while_body->stmts().push_back(next_label);
00180     while_body->stmts().push_back(next_stmt);
00181   } else {
00182     while_body->stmts().push_back(the_for->body());
00183   }
00184 
00185   new_block->stmts().push_back(init);
00186   new_block->stmts().push_back(while_loop);
00187 
00188   return new_block;
00189 }
00190 
00191 Node * LoopDismantle::at_do(doNode * the_do, Order ord) {
00192   // do {
00193   //   body; ...
00194   //   break; ...
00195   //   continue; ...
00196   // } while ( cond );
00197   // =>
00198   // {
00199   //   __body: ;
00200   //   body; ...
00201   //   goto __exit; ...
00202   //   goto __test; ...
00203   //   __test: ;
00204   //   if ( !cond ) goto __exit;
00205   //   goto __body;
00206   //   __exit: ;
00207   // }
00208 
00209   blockNode * new_block = new blockNode(NULL, NULL, the_do->coord());
00210   labelNode * body_label = DismantleUtil::new_label(the_do->coord());
00211   labelNode * test_label = DismantleUtil::new_label(the_do->coord());
00212   labelNode * exit_label = DismantleUtil::new_label(the_do->coord());
00213   exprNode * not_cond = DismantleUtil::Not(the_do->cond());
00214   gotoNode * goto_exit = new gotoNode(exit_label);
00215   ifNode * test_cond = new ifNode(not_cond, goto_exit, NULL, the_do->coord());
00216   gotoNode * goto_body = new gotoNode(body_label);
00217   gotoNode * goto_test = new gotoNode(test_label);
00218 
00219   new_block->stmts().push_back(body_label);
00220   // replace 'break' & 'continue' with goto_exit & goto_test (resp).
00221   BreakContinueChanger bcc(the_do, exit_label, test_label);
00222   new_block->stmts().push_back((stmtNode *) the_do->body()->change(bcc));
00223 
00224   new_block->stmts().push_back(test_label);
00225   new_block->stmts().push_back(test_cond);
00226   new_block->stmts().push_back(goto_body);
00227   new_block->stmts().push_back(exit_label);
00228 
00229   return new_block;
00230 }
00231 
00232 TernaryDismantle::TernaryDismantle(void):
00233   Changer(Both, Subtree, false),
00234   _cur_stmt(NULL), _in_type(0)
00235 {}
00236 
00237 Node * TernaryDismantle::at_stmt(stmtNode * the_stmt, Order ord) {
00238   if ( ord == Preorder ) {
00239     _cur_stmt = the_stmt;
00240   } else {
00241     _cur_stmt = NULL;
00242     if ( _new_block[the_stmt] ) {
00243       _new_block[the_stmt]->stmts().push_back(the_stmt);
00244       blockNode * ret = _new_block[the_stmt];
00245       // we want to re-change the block, b/c there may be additional 
00246       // ternaryNodes that we didn't/couldn't dismantle on this pass
00247       TernaryDismantle td;
00248       return ret->change(td);
00249     }
00250   }
00251   return the_stmt;
00252 }
00253 
00254 Node * TernaryDismantle::at_ternary(ternaryNode * the_ternary,
00255                                              Order ord) {
00256   if (! _cur_stmt || _in_type>0) {
00257     return the_ternary; // we're not in a statement.
00258   }
00259   if ( ord == Preorder ) {
00260     // a ? b : c
00261     // =>
00262     // {
00263     //   if ( a )
00264     //     __tmp = b;
00265     //   else
00266     //     __tmp = c;
00267     // } (returns __tmp)
00268     if ( !_new_block[_cur_stmt] )
00269       _new_block[_cur_stmt] = new blockNode(NULL, NULL, the_ternary->coord());
00270 
00271     declNode * result_decl;
00272     typeNode * result_type = the_ternary->type();
00273     bool is_void = result_type->is_void();
00274     exprstmtNode * assign_true,
00275                  * assign_false;
00276     if(is_void) {
00277       /* this is to handle case like "(cond) ? (void) 0 : __assert(...)"
00278        * ie. both true and false branches are void expressions, so this
00279        * ternaryNode should not be replaced by assignment statements.
00280        */ 
00281       assign_true = new exprstmtNode(the_ternary->true_br());
00282       assign_false = new exprstmtNode(the_ternary->false_br());
00283     } else {
00284       result_decl = DismantleUtil::new_temp_decl(the_ternary->type(),
00285                                                  the_ternary->coord());
00286       _new_block[_cur_stmt]->decls().push_back(result_decl);
00287       assign_true = new exprstmtNode(new binaryNode('=',
00288                         new idNode(result_decl),
00289                         the_ternary->true_br(),
00290                         the_ternary->coord()));
00291       assign_true->expr()->type((typeNode*)ref_clone_changer::clone(result_type,
00292                                                                     false));
00293       assign_false =
00294         new exprstmtNode(new binaryNode('=',
00295                 new idNode(result_decl),
00296                 the_ternary->false_br(),
00297                 the_ternary->coord()));
00298       assign_false->expr()->type(
00299         (typeNode*)ref_clone_changer::clone(result_type, false));
00300     }
00301     ifNode * new_if = new ifNode(the_ternary->cond(),
00302                                  assign_true,
00303                                  assign_false,
00304                                  the_ternary->coord());
00305     _new_block[_cur_stmt]->stmts().push_back(new_if);
00306     if(is_void)
00307       return NULL;
00308     else
00309       return new idNode(result_decl, the_ternary->coord());
00310   }
00311   return the_ternary;
00312 }
00313 
00314 Node * TernaryDismantle::at_type(typeNode * the_type, Order ord) {
00315   if (ord==Preorder) _in_type++;
00316   else _in_type--;
00317   return the_type;
00318 }
00319 
00320 SelectionDismantle::SelectionDismantle(void):
00321   Changer(Both, Subtree, false),
00322   _cur_stmt(NULL),
00323   _in_expr(false)
00324 {}
00325 
00326 
00327 // Do the following 4 methods belong in a different Changer?  They don't
00328 // really dismantle selectionNodes, they only transform && and || into 
00329 // equivalent ifNodes.
00330 Node * SelectionDismantle::andand_oror_in_expr(stmtNode * the_stmt,
00331                                                         Order ord) {
00332   if ( ord == Preorder ) {
00333     _in_expr = true;
00334   } else { // ord == Postorder
00335     _in_expr = false;
00336     if ( _expr_block[the_stmt] ) {
00337       blockNode * ret = _expr_block[the_stmt];
00338       ret->stmts().push_back(the_stmt);
00339       
00340       // must do this so that the newly generated "if ( a && b )"
00341       // are dismantled properly
00342       SelectionDismantle sd;
00343       return ret->change(sd);
00344     }
00345   }
00346   return the_stmt;
00347 }
00348 
00349 Node * SelectionDismantle::at_exprstmt(exprstmtNode * the_exprstmt,
00350                                                 Order ord) {
00351   _cur_stmt = the_exprstmt;
00352   return andand_oror_in_expr(the_exprstmt, ord);
00353 }
00354 
00355 Node * SelectionDismantle::at_return(returnNode * the_return,
00356                                               Order ord) {
00357   _cur_stmt = the_return;
00358   return andand_oror_in_expr(the_return, ord);
00359 }
00360 
00361 Node * SelectionDismantle::at_binary(binaryNode * the_binary,
00362                                               Order ord) {
00363   if ( ord == Preorder ) {
00364     Operator * op = the_binary->op();
00365     if ( _in_expr
00366          && ( op->id() == Operator::ANDAND
00367               || op->id() == Operator::OROR ) ) {
00368       // (in an expression) ... b && c ...; // (or ||)
00369       // =>
00370       // { 
00371       //   tmp = 0;
00372       //   if ( b && c) // (or ||)
00373       //     tmp = 1;
00374       // }
00375       // ... tmp ...; (returns tmp)
00376       if(! _expr_block[_cur_stmt])
00377         _expr_block[_cur_stmt] = new blockNode(NULL, NULL, the_binary->coord());
00378       declNode * temp_decl = 
00379         DismantleUtil::new_temp_decl(the_binary->type(),
00380                                               the_binary->coord());
00381       typeNode * bin_type = the_binary->type();
00382       exprstmtNode * assign_zero =
00383         new exprstmtNode(new binaryNode('=', new idNode(temp_decl),
00384                                         new constNode(constant::constant(0)),
00385                                         the_binary->coord()));
00386       assign_zero->expr()->type((typeNode *) ref_clone_changer::clone(bin_type,
00387                                                                       false));
00388       exprstmtNode * assign_one =
00389         new exprstmtNode(new binaryNode('=', new idNode(temp_decl),
00390                                         new constNode(constant::constant(1)),
00391                                         the_binary->coord()));
00392       assign_one->expr()->type((typeNode *) ref_clone_changer::clone(bin_type,
00393                                                                      false));
00394       ifNode * new_if = new ifNode(the_binary, assign_one, NULL,
00395                                    the_binary->coord());
00396       _expr_block[_cur_stmt]->decls().push_back(temp_decl);
00397       _expr_block[_cur_stmt]->stmts().push_back(assign_zero);
00398       _expr_block[_cur_stmt]->stmts().push_back(new_if);
00399       return new idNode(temp_decl);
00400     }
00401   } // end if ( ord == Preorder )
00402   return the_binary;
00403 }
00404 
00405 // TODO:  add comments from 1/9/2003 - #1 notes
00406 Node * SelectionDismantle::at_switch(switchNode * the_switch, 
00407                                               Order ord) {
00408   _cur_stmt = the_switch;
00409   if ( ord == Preorder ) {
00410     // switch ( expr ) {
00411     //   body;
00412     //   case a:
00413     //     bodya;
00414     //   case b:
00415     //     bodyb;
00416     //   [default:
00417     //     bodyn;]
00418     // }
00419     // =>
00420     // { tmp = expr;
00421     //   if ( tmp == a ) goto bodya_label;
00422     //   if ( tmp == b ) goto bodyb_label;
00423     //   goto default_label;
00424     //   bodya_label: ;
00425     //   bodya; // with 'break' replaced by 'goto break_label;'
00426     //   bodyb_label: ;
00427     //   bodyb; // ditto
00428     //   default_label: ;
00429     //   bodyn; // ditto
00430     //   break_label: ;
00431     // }
00432     // Note:  we currently leave the caseNode's in the body and they are
00433     //        later removed by DismantleFlatten
00434     blockNode * new_block = new blockNode(NULL, NULL, the_switch->coord());
00435     exprNode * switch_expr = the_switch->expr();
00436     // TODO: if the switch_expr is an idNode or a constNode, we don't really
00437     //       need the temp_decl.
00438     declNode * temp_decl = 
00439       DismantleUtil::new_temp_decl(switch_expr->type(),
00440                                             the_switch->coord());
00441     new_block->decls().push_back(temp_decl);
00442     
00443     exprstmtNode * assign_expr = 
00444       new exprstmtNode(new binaryNode('=', new idNode(temp_decl),
00445                                       switch_expr, the_switch->coord()) );
00446     assign_expr->expr()->type((typeNode *) 
00447                               ref_clone_changer::clone(temp_decl->type(),
00448                                                        false));
00449     new_block->stmts().push_back(assign_expr);
00450     
00451     labelNode * break_label = 
00452       DismantleUtil::new_label(the_switch->coord());
00453     labelNode * default_label = break_label;
00454     
00455     for( target_list_p p = the_switch->cases().begin();
00456          p != the_switch->cases().end();
00457          p++ ) {
00458       if ( (*p)->typ() == Case ) { // make sure that it isn't Label
00459         caseNode * the_case = (caseNode *) *p;
00460         if ( the_case->expr() ) {
00461           binaryNode * case_cmp = new binaryNode(Operator::EQ,
00462                                                  new idNode(temp_decl),
00463                                                  the_case->expr(),
00464                                                  the_case->coord());
00465           case_cmp->type((typeNode *)
00466                          ref_clone_changer::clone(temp_decl->type(),
00467                                                   false));
00468           labelNode * case_label = 
00469             DismantleUtil::new_label(the_case->coord());
00470           ifNode * case_if = new ifNode(case_cmp, 
00471                                         new gotoNode(case_label),
00472                                         NULL,
00473                                         the_case->coord());
00474           new_block->stmts().push_back(case_if);
00475           the_case->stmt()->stmts().push_front(case_label);
00476         } else { // the default case
00477           default_label = DismantleUtil::new_label(the_case->coord());
00478           the_case->stmt()->stmts().push_front(default_label);
00479         }
00480       }
00481     }
00482     new_block->stmts().push_back(new gotoNode(default_label, 
00483                                               the_switch->coord()));
00484     // replace 'break's with 'goto <break_label>'
00485     BreakContinueChanger bcc(the_switch, break_label, NULL);
00486     new_block->stmts().push_back((stmtNode *) the_switch->stmt()->change(bcc));
00487 
00488     new_block->stmts().push_back(break_label);
00489     
00490     return new_block;
00491   } // end if ( ord == Preorder )
00492   return the_switch;
00493 }
00494 
00495 indexNode * SelectionDismantle::comparison_operand
00496 (
00497  exprNode * orig_operand, 
00498  blockNode * temp_block
00499  )
00500 {
00501   indexNode * ret = NULL;
00502   if ( orig_operand->typ() == Const ||
00503        orig_operand->typ() == Id )
00504     ret = (indexNode *) orig_operand;
00505   else {
00506     declNode * temp_decl =
00507       DismantleUtil::new_temp_decl(orig_operand->type(),
00508                                             orig_operand->coord());
00509     exprstmtNode * assign_temp =
00510       new exprstmtNode(new binaryNode('=', new idNode(temp_decl),
00511                                       orig_operand));
00512     assign_temp->expr()->type((typeNode *)
00513                               ref_clone_changer::clone(temp_decl->type(),
00514                                                        false));
00515     temp_block->decls().push_back(temp_decl);
00516     temp_block->stmts().push_back(assign_temp);
00517     ret = new idNode(temp_decl);
00518   }
00519   return ret;
00520 }
00521 
00522 // TODO: factor into smaller chunks?
00523 Node * SelectionDismantle::at_if(ifNode * the_if, Order ord) {
00524   _cur_stmt = the_if;
00525   if ( ord == Preorder ) {
00526     blockNode * new_block = new blockNode(NULL, NULL, the_if->coord());
00527     // transform
00528     // if ( a )
00529     //   <null>
00530     // else
00531     //   <null>
00532     // =>
00533     // a;
00534     if ( ! the_if->true_br()
00535          && ! the_if->false_br() )
00536       return new exprstmtNode(the_if->expr());
00537 
00538     // transform
00539     // if ( a )
00540     //   <null>
00541     // else
00542     //   b;
00543     // =>
00544     // if ( ! a )
00545     //   b;
00546     if ( !the_if->true_br() ) {
00547       the_if->expr(DismantleUtil::Not(the_if->expr()));
00548       the_if->true_br(the_if->false_br());
00549       the_if->false_br(NULL);
00550     }
00551 
00552     // transform
00553     // if ( a )
00554     //   b;
00555     // else
00556     //   c;
00557     // into
00558     // if ( a ) 
00559     //  { b; goto <exit_label>; }
00560     // <else_label>: ;
00561     // c;
00562     // <exit_label>: ;
00563     labelNode* exit_label = DismantleUtil::new_label(the_if->coord());
00564     labelNode * else_label = exit_label;
00565     if ( the_if->false_br() ) {
00566       else_label =
00567         DismantleUtil::new_label(the_if->false_br()->coord());
00568       new_block->stmts().push_back(else_label);
00569       new_block->stmts().push_back(the_if->false_br());
00570       new_block->stmts().push_back(exit_label);
00571       the_if->true_br()->stmts().push_back(new gotoNode(exit_label));
00572       the_if->false_br(DismantleUtil::empty_block());
00573     } else {
00574       new_block->stmts().push_back(exit_label);
00575     }
00576     
00577     if ( the_if->expr()->typ() == Binary ) {
00578       binaryNode * test = (binaryNode *) the_if->expr();
00579       if ( test->op()->id() == Operator::ANDAND ) {
00580         // if ( a && b ) foo;
00581         // =>
00582         // if ( a )
00583         //    if ( b )
00584         //       foo;
00585         ifNode * inner_if = new ifNode(test->right(),
00586                                        the_if->true_br(),
00587                                        NULL,
00588                                        the_if->coord());
00589         ifNode * outer_if = new ifNode(test->left(),
00590                                        inner_if,
00591                                        NULL,
00592                                        the_if->coord());
00593         new_block->stmts().push_front(outer_if);
00594         return new_block;
00595       } else if ( test->op()->id() == Operator::OROR ) {
00596         // if ( a || b ) foo;
00597         // =>
00598         // if ( a ) goto then;
00599         // if ( b ) { 
00600         //   then: ;
00601         //   foo;
00602         // }
00603         labelNode * then_label =
00604           DismantleUtil::new_label(the_if->coord());
00605         ifNode * first_if = new ifNode(test->left(),
00606                                        new gotoNode(then_label),
00607                                        NULL,
00608                                        the_if->coord());
00609         ifNode * second_if = new ifNode(test->right(),
00610                                         the_if->true_br(),
00611                                         NULL,
00612                                         the_if->coord());
00613         second_if->true_br()->stmts().push_front(then_label);
00614         new_block->stmts().push_front(second_if);
00615         new_block->stmts().push_front(first_if);
00616         return new_block;
00617       } else if ( test->op()->is_comparison() ) {
00618         // if ( a <relop> b ) c;
00619         // =>
00620         // a' = a; /* if a ! indexNode */
00621         // b' = b; /* if b ! indexNode */
00622         // if ( a' <!relop> b' ) goto skip;
00623         // c;
00624         // skip: ;
00625         blockNode * sub_block = new blockNode(NULL, NULL);
00626         indexNode * left = comparison_operand(test->left(), sub_block);
00627         indexNode * right = comparison_operand(test->right(), sub_block);
00628         assert(left != NULL && right != NULL);
00629         Operator * op = test->op();
00630         conditiongotoNode * new_if =
00631           new conditiongotoNode(else_label, left, 
00632                                 DismantleUtil::not_relop[op->id()],
00633                                 right, the_if->coord());
00634         sub_block->stmts().push_back(new_if);
00635         sub_block->stmts().push_back(the_if->stmt());
00636         new_block->stmts().push_front(sub_block);
00637         return new_block;
00638       }
00639     } else if ( the_if->expr()->typ() == Const ||
00640                 the_if->expr()->typ() == Id ) {
00641       // TODO: should this be the type of the expr()?
00642       // yes, but is this still okay?
00643       constNode * zero = new constNode(constant::constant(0));
00644       indexNode * left = (indexNode *) the_if->expr();
00645       conditiongotoNode * new_if =
00646         new conditiongotoNode(else_label, left, Operator::EQ, zero,
00647                               the_if->coord());
00648       new_block->stmts().push_front(the_if->stmt());
00649       new_block->stmts().push_front(new_if);
00650       return new_block;
00651     } else if ( the_if->expr()->typ() == Unary ) {
00652       unaryNode * unary_expr = (unaryNode *) the_if->expr();
00653       if ( unary_expr->op()->id() == '!' ) {
00654         // if ( !a ) b;
00655         // =>
00656         // if ( a ) ; else b;
00657         ifNode * new_if = new ifNode(unary_expr->expr(),
00658                                      DismantleUtil::empty_block(),
00659                                      the_if->true_br(),
00660                                      the_if->coord());
00661         new_block->stmts().push_front(new_if);
00662         return new_block;
00663       }
00664     }
00665 
00666     // the_if->expr() is either Call, Unary, or arithmetic binary
00667     exprNode * test = the_if->expr();
00668     declNode * temp_decl =
00669       DismantleUtil::new_temp_decl(test->type(),
00670                                             test->coord());
00671     exprstmtNode * assign_temp =
00672       new exprstmtNode(new binaryNode('=', new idNode(temp_decl),
00673                                       test, the_if->coord()));
00674     assign_temp->expr()->type((typeNode *)
00675                               ref_clone_changer::clone(temp_decl->type(),
00676                                                        false));
00677     the_if->expr(new idNode(temp_decl));
00678     new_block->decls().push_back(temp_decl);
00679     new_block->stmts().push_front(the_if);
00680     new_block->stmts().push_front(assign_temp);
00681     return new_block;
00682   }
00683   return the_if;
00684 }
00685 
00686 
00687 Node * SelectionDismantle::at_stmt(stmtNode * the_stmt, Order ord) {
00688   _cur_stmt = the_stmt;
00689   return the_stmt;
00690 }
00691 
00692 ReturnDismantle::ReturnDismantle(void):
00693   Changer(Preorder, Subtree, false)
00694 {}
00695 
00696 Node * ReturnDismantle::at_proc(procNode * the_proc, Order ord) {
00697   if ( !the_proc->return_label() ) {
00698     labelNode * return_label = 
00699       DismantleUtil::new_label(the_proc->coord()); // ???
00700     the_proc->return_label(return_label);
00701     blockNode * return_block = new blockNode(NULL, NULL);
00702     return_block->stmts().push_front(return_label);
00703     the_proc->body()->stmts().push_back(return_block);
00704     returnNode * proc_return = NULL;
00705     funcNode * return_type = (funcNode *) the_proc->decl()->type();
00706     if ( ! return_type->returns()->is_void() ) { // the proc returns non-void
00707       declNode * return_decl =
00708         DismantleUtil::new_temp_decl(return_type->type(),
00709                                               the_proc->coord()); // ???
00710       the_proc->body()->decls().push_back(return_decl);
00711       the_proc->return_decl(return_decl);
00712       proc_return = new returnNode(new idNode(return_decl), the_proc, true);
00713     } else { // the_proc returns void
00714       proc_return = new returnNode(NULL, the_proc, true);
00715     }
00716     return_block->stmts().push_back(proc_return);
00717   }
00718   return the_proc;
00719 }
00720 
00721 Node * ReturnDismantle::at_return(returnNode * the_return, 
00722                                            Order ord) {
00723   stmtNode * ret = the_return;
00724   if ( ! the_return->proc_exit() ) {
00725     procNode * curr_proc = the_return->proc();
00726     blockNode * new_block = new blockNode(NULL, NULL, the_return->coord());
00727 
00728     if ( the_return->expr() ) { // function returns non-void
00729       exprstmtNode * assign_return = 
00730         new exprstmtNode(new binaryNode('=',
00731                                         new idNode(curr_proc->return_decl(),
00732                                                    the_return->coord()),
00733                                         the_return->expr(),
00734                                         the_return->coord()));
00735       assign_return->expr()->type(the_return->expr()->type());
00736       new_block->stmts().push_back(assign_return);
00737     }
00738 
00739     gotoNode * goto_return = new gotoNode(curr_proc->return_label(),
00740                                           the_return->coord());
00741     new_block->stmts().push_back(goto_return);
00742     ret = new_block;
00743   } // else, this is the already dismantled return for the proc
00744   return ret;
00745 }

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