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  

asm_gen_walker.cc

Go to the documentation of this file.
00001 // $Id: asm_gen_walker.cc,v 1.7 2003/08/11 17:38:51 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 "asm_gen_walker.h"
00040 #include "lir_flow_walker.h"
00041 #include "LIR.h"
00042 #include "hash_set_ex.h"
00043 #include "ref_clone_changer.h"
00044 
00045 asm_gen_walker::asm_gen_walker ():Walker (Both, NodeOnly)
00046 {
00047   _unit = NULL;
00048   _pOutFile = NULL;
00049 }
00050 
00051 asm_gen_walker::~asm_gen_walker ()
00052 {
00053 }
00054 
00055 void
00056 asm_gen_walker::at_unit (unitNode * the_unit, Order ord)
00057 {
00058   if (ord == Preorder) {
00059     // save this
00060     _unit = the_unit;
00061 
00062     // open output file
00063 //     string file = _unit->output_file ();  // output to <file>.p.c
00064     string file = _unit->input_file();
00065     file[file.size()-1] = 's';  // output to <file>.s
00066     _pOutFile = fopen (file.c_str (), "wt");
00067     if (!_pOutFile) {
00068       fprintf (stderr, "Can't open output file '%s' for writing.",
00069                file.c_str ());
00070       assert (false);
00071     }
00072 
00073     // write a header
00074     fprintf (_pOutFile, ".file \"%s\"\n\n", _unit->input_file ().c_str ());
00075 
00076     // throw out a begin unit instruction
00077     LirInst *begin = LIR::BeginUnit (_unit);
00078     emit (begin);
00079     delete begin;
00080 
00081     // add all other unit instructions
00082     emit (_unit->instructions ());
00083 
00084     // process all defs
00085     const def_list & defs = _unit->defs ();
00086     def_list::const_iterator it = defs.begin ();
00087     while (it != defs.end ())
00088       (*(it++))->walk (*this);
00089   }
00090   else {
00091     // throw out an end unit instruction
00092     LirInst *end = LIR::EndUnit (_unit);
00093     emit (end);
00094     delete end;
00095 
00096     // close the output file
00097     fprintf (_pOutFile, "\n\n");
00098     fclose (_pOutFile);
00099     _pOutFile = NULL;
00100 
00101     // no unit anymore
00102     _unit = NULL;
00103   }
00104 }
00105 
00106 void
00107 asm_gen_walker::at_proc (procNode * the_proc, Order ord)
00108 {
00109   // ignore second pass
00110   if (ord != Preorder) {
00111     _proc = NULL;
00112     return;
00113   }
00114 
00115   // save this
00116   _proc = the_proc;
00117 
00118 #define CHECK_REG( reg ) \
00119 do { \
00120         if ( ! CBZ::ArchInfo.get_reg_by_index( (reg).num(), dummy ) ) \
00121                 CBZFAIL(("Instruction '%s' uses virtual register.\n" \
00122                         "Did you forget to specify a register allocation " \
00123                          "phase or -noreg on the command line?", \
00124                          inst->to_string().c_str())); \
00125 } while (0)
00126 
00127   // sanity check - make sure there are no vitual registers in here
00128   instruction_list & insts = the_proc->instructions ();
00129   instruction_list_p it = insts.begin ();
00130   for (; it != insts.end (); ++it) {
00131     LirInst *inst = *it;
00132     Register dummy;
00133     if (inst->has_opnd1 ())
00134       CHECK_REG (inst->opnd1);
00135     if (inst->has_opnd2 ())
00136       CHECK_REG (inst->opnd2._reg);
00137     if (inst->has_base ())
00138       CHECK_REG (inst->memBase);
00139     if (inst->has_offset ())
00140       CHECK_REG (inst->memOffset._reg);
00141     if (inst->has_dest ())
00142       CHECK_REG (inst->dest);
00143   }
00144 
00145 #undef CHECK_REG
00146 
00147   // add code for handling callee-save registers
00148   doCalleeSave ();
00149 
00150   // add code for caller-save registers
00151   doCallerSave ();
00152 
00153   // finally, compute the total size of the stack frame
00154   computeStackFrameSize ();
00155 
00156   // emit all instructions
00157   emit (insts);
00158 
00159 }
00160 
00161 void
00162 asm_gen_walker::computeStackFrameSize ()
00163 {
00164   assert (_proc);
00165 
00166   // decide how big we think the stack frame has to be.
00167   //      this is the sum of any extra space specified in the
00168   //      arch spec, plus the size of stack locals, plus space
00169   //      for arguments to called procedures.
00170 
00171   // start with the size of locals
00172   unsigned int stackSize = _proc->get_locals_size ();
00173 
00174   // find out max size of function arguments
00175   unsigned int procArgSize = 0;
00176   instruction_list & insts = _proc->instructions ();
00177   instruction_list_p it = insts.begin ();
00178   for (; it != insts.end (); ++it) {
00179     LirInst & inst = **it;
00180     if (inst.instruction == mn_Call) {
00181       // see how many bytes this call takes
00182       if (procArgSize < inst.stack_arg_bytes ())
00183         procArgSize = inst.stack_arg_bytes ();
00184     }
00185   }
00186 
00187   // add in size of function args and bottom buffer and compute the total size
00188   stackSize += procArgSize;
00189   stackSize += CBZ::ArchInfo.get_stack_extra_bottom ();
00190   if (stackSize < CBZ::ArchInfo.get_stack_frame_min_size ())
00191     stackSize = CBZ::ArchInfo.get_stack_frame_min_size ();
00192 
00193   // align the size as necessary
00194   unsigned int align = CBZ::ArchInfo.get_stack_align ();
00195   stackSize = ((stackSize + align - 1) / align) * align;
00196 
00197   // save this in the proc for later use
00198   _proc->stack_frame_size (stackSize);
00199 }
00200 
00201 void
00202 asm_gen_walker::doCalleeSave ()
00203 {
00204   assert (_proc);
00205   instruction_list & insts = _proc->instructions ();
00206 
00207   // what does callee save?
00208   const arch_info::register_info_list & calleeSaveRegs =
00209     CBZ::ArchInfo.get_regs_callee_save ();
00210   if (calleeSaveRegs.size () == 0)
00211     return;
00212 
00213   typedef hash_set_ex < unsigned int >regSet;
00214 
00215   // make a set of this.
00216   regSet calleeSaveRegSet;
00217   arch_info::register_info_list::const_iterator csrit =
00218     calleeSaveRegs.begin ();
00219   while (csrit != calleeSaveRegs.end ())
00220     calleeSaveRegSet.insert ((*(csrit++))->_id);
00221 
00222   // make a single forward pass over instructions to see which registers
00223   //      are used and to make a list of all return instructions that need to 
00224   //      get restore code added
00225   vector < instruction_list_p > returns;
00226   regSet changedRegSet;
00227   instruction_list_p it = insts.begin ();
00228   for (; it != insts.end (); ++it) {
00229     LirInst & inst = **it;
00230 
00231     // if it's a return we'll need to patch it later
00232     if (inst.instruction == mn_Return)
00233       returns.push_back (it);
00234 
00235     // if it has a destination add that register to changed registers
00236     if (inst.has_dest ())
00237       changedRegSet.insert (inst.dest.num ());
00238 
00239     // also add in any kill registers for this instruction
00240     arch_info::register_info_list killRegs;
00241     CBZ::ArchInfo.get_instruction_kill_regs (&inst, killRegs);
00242     arch_info::register_info_list_p kit = killRegs.begin ();
00243     for (; kit != killRegs.end (); ++kit)
00244       changedRegSet.insert ((*kit)->_id);
00245   }
00246 
00247   // intersect these sets
00248   changedRegSet &= calleeSaveRegSet;
00249 
00250   // did we change anything?  if not we have no work to do
00251   if (changedRegSet.size () == 0)
00252     return;
00253 
00254   // find begin proc - should be beginning
00255   instruction_list_p firstRealInst = insts.begin ();
00256   while ((*firstRealInst)->instruction != mn_BeginProc
00257          && firstRealInst != insts.end ())
00258     firstRealInst++;
00259   assert (firstRealInst != insts.end ());
00260   LirInst *pBeginProc = *firstRealInst;
00261   firstRealInst++;
00262 
00263   // add save code after begin proc, and restore code before each return
00264   regSet::iterator toSave = changedRegSet.begin ();
00265   for (; toSave != changedRegSet.end (); ++toSave) {
00266     // allocate a temporary to save this register
00267     Register reg;
00268     typeNode * the_type;
00269     declNode * decl;
00270     createTempForRegSave (*toSave, reg, the_type, decl);
00271 
00272     // make instruction to store this register into the stack
00273     LirInst *pStore = LIR::Store (the_type, reg, decl, Register::getRegFp (),
00274                                   DATA_CONTENTS_FRAMEP,
00275                                   decl->storage_location ()._stack_offset,
00276                                   NULL);
00277 
00278     // add this after the previous thing we added, before the first real
00279     // instruction
00280     insts.insert (firstRealInst, pStore);
00281 
00282     // add instructions to restore it before each return
00283     vector < instruction_list_p >::iterator rtIt = returns.begin ();
00284     for (; rtIt != returns.end (); ++rtIt) {
00285       // make the load instruction
00286       LirInst *pLoad = LIR::Load (the_type, reg, decl, Register::getRegFp (),
00287                                   DATA_CONTENTS_FRAMEP,
00288                                   decl->storage_location ()._stack_offset,
00289                                   NULL);
00290 
00291       // add this before the return instruction
00292       insts.insert (*rtIt, pLoad);
00293       assert ((**rtIt)->instruction == mn_Return);
00294     }
00295   }
00296 
00297 }
00298 
00299 void
00300 asm_gen_walker::doCallerSave ()
00301 {
00302   assert (_proc);
00303   instruction_list & insts = _proc->instructions ();
00304 
00305   // make set of caller-save regs
00306   reg_id_set caller_save;
00307   const arch_info::register_info_list & csave =
00308     CBZ::ArchInfo.get_regs_caller_save ();
00309   arch_info::register_info_list::const_iterator cs = csave.begin ();
00310   for (; cs != csave.end (); ++cs)
00311     caller_save |= (*cs)->_id;
00312 
00313   // compute liveness
00314   inst_to_reg_id_map liveRegs;
00315   lir_flow_walker::computeRegisterLiveness (insts, liveRegs);
00316 
00317   // for debugging - trace out liveness for each instruction
00318 #if 0
00319   {
00320     cout << "DEBUG:" << endl;
00321     cout << "Liveness:" << endl;
00322     instruction_list_p it = insts.begin ();
00323     for (; it != insts.end (); ++it) {
00324       cout << "    Live: ";
00325       reg_id_set_p live = liveRegs[*it].begin ();
00326       for (; live != found->second.end (); ++live) {
00327         arch_info::register_info * info =
00328           CBZ::ArchInfo.get_all_regs ()[*live];
00329         cout << info->_name << " ";
00330       }
00331       cout << endl;
00332       cout << "Inst: " << **it << endl;
00333     }
00334     cout << "END DEBUG" << endl;
00335   }
00336 #endif
00337 
00338   // now do save/load for each call instruction - start by finding
00339   // mn_CallPre instructions
00340   instruction_list_p it = insts.begin ();
00341   Register regRetFixed = Register::getRegRetValFixed ();
00342   Register regRetFloat = Register::getRegRetValFloat ();
00343   for (; it != insts.end (); ++it) {
00344     // grab this instruction
00345     LirInst *inst = *it;
00346 
00347     // skip to the next pre-call instruction
00348     if (inst->instruction != mn_CallPre)
00349       continue;
00350 
00351     // any live caller-save regs?
00352     reg_id_set live = liveRegs[inst];
00353     live &= caller_save;
00354     if (live.size () == 0)
00355       continue;
00356 
00357     // get an iterator pointing right after sequencer
00358     instruction_list_p sequence = it;
00359     sequence++;
00360 
00361     // find the actual call
00362     LirInst *call = NULL;
00363     while (it != insts.end () && (*it)->instruction != mn_Call)
00364       it++;
00365     assert (it != insts.end ());
00366     call = *it;
00367     instruction_list_p postCall = it;
00368     postCall++;
00369     assert (postCall != insts.end ());
00370 
00371     // decide on the expected return value register
00372     typeNode * the_type = call->nodeExtra->type();
00373     Register *pRegRet = NULL;
00374     if ( the_type->is_float() )
00375       pRegRet = &regRetFloat;
00376     else if ( the_type->is_integer() || the_type->is_pointer() )
00377       pRegRet = &regRetFixed;
00378 
00379     // save anything that's live here
00380     reg_id_set_p toSave = live.begin ();
00381     for (; toSave != live.end (); ++toSave) {
00382       // we never save return value register
00383       assert (*toSave != pRegRet->num ());
00384 
00385       // allocate a temporary to save this register
00386       Register reg;
00387       typeNode * the_type;
00388       declNode * decl;
00389       createTempForRegSave (*toSave, reg, the_type, decl);
00390 
00391       // make instruction to store this register into the stack
00392       LirInst *pStore = LIR::Store (the_type, reg, decl, Register::getRegFp (),
00393                                     DATA_CONTENTS_FRAMEP,
00394                                     decl->storage_location ()._stack_offset,
00395                                     NULL);
00396 
00397       // add this right after the sequencing instruction
00398       insts.insert (sequence, pStore);
00399 
00400       // make the load instruction to reload this from the stack
00401       LirInst *pLoad = LIR::Load (the_type, reg, decl, Register::getRegFp (),
00402                                   DATA_CONTENTS_FRAMEP,
00403                                   decl->storage_location ()._stack_offset,
00404                                   NULL);
00405 
00406       // add this after the call instruction
00407       insts.insert (postCall, pLoad);
00408     }
00409   }
00410 }
00411 
00412 void
00413 asm_gen_walker::createTempForRegSave (unsigned int id, Register & reg,
00414                                       typeNode *& the_type, declNode * &decl)
00415 {
00416   // get the register
00417   CBZ::ArchInfo.get_reg_by_index (id, reg);
00418   assert (reg.type () == reg_gpr || reg.type () == reg_fpr);
00419   bool isgpr = (reg.type () == reg_gpr);
00420   the_type = (isgpr) ? CBZ::ArchInfo.get_reg_data_type_gpr () 
00421                      : CBZ::ArchInfo.get_reg_data_type_fpr ();
00422 
00423   // make a temp decl and allocate stack storage
00424   typeNode * declType = (typeNode *) ref_clone_changer::clone(the_type, false);
00425   declType->alloc_size(CBZ::ArchInfo.get_data_size(declType));
00426   declType->alloc_align(CBZ::ArchInfo.get_data_align(declType));
00427   decl = new declNode (reg.to_string ().c_str (), declNode::AUTO, 
00428                        declType, NULL, NULL);
00429   _proc->alloc_stack_local (decl);
00430 }
00431 
00432 void
00433 asm_gen_walker::emit (const LirInst * inst)
00434 {
00435   assert (_pOutFile);
00436   if (!_pOutFile)
00437     return;
00438   if (!inst->should_emit ())
00439     return;
00440 
00441   // generate code
00442   vector < string > code;
00443   if (!CBZ::ArchInfo.get_code_for_instruction (inst, code))
00444     CBZFAIL (("Can't emit instruction '%s'  because there is no code "
00445               "template for such an instruction in the architecture spec.", 
00446               inst->to_string ().c_str ()));
00447 
00448   // emit each line to the file
00449   int i, sz = (int) code.size ();
00450   for (i = 0; i < sz; ++i)
00451     fprintf (_pOutFile, "%s\n", code[i].c_str ());
00452 }
00453 
00454 void
00455 asm_gen_walker::emit (const instruction_list & insts)
00456 {
00457   assert (_pOutFile);
00458   if (!_pOutFile)
00459     return;
00460 
00461   // do each one
00462   instruction_list::const_iterator it = insts.begin ();
00463   for (; it != insts.end (); ++it) {
00464 //     cout << (*it)->to_string() << endl;
00465     emit (*it);
00466   }
00467 }

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