spillgen.cc

Go to the documentation of this file.
00001 #include <lestes/backend_v2/structs/func_data.g.hh>
00002 #include <lestes/backend_v2/intercode/ge.g.hh>
00003 #include <lestes/backend_v2/intercode/pi.g.hh>
00004 #include <lestes/backend_v2/workers/spillgen.g.hh>
00005 #include <lestes/backend_v2/workers/alloc_int_finder.g.hh>
00006 #include <lestes/backend_v2/workers/bb_finder.g.hh>
00007 #include <lestes/backend_v2/workers/helpers.hh>
00008 #include <lestes/md/mem/mem_alloc_manager.g.hh>
00009 #include <lestes/md/registers/tm_register.g.hh>
00010 #include <lestes/md/registers/move_generator.g.hh>
00011 #include <lestes/md/instructions/tm_instr.g.hh>
00012 #include <lestes/md/types/tm_data_type.g.hh>
00013 #include <lestes/lang/cplus/sem/ss_declaration.g.hh>
00014 
00015 package(lestes);
00016 package(backend_v2);
00017 package(workers);
00018 
00019 using namespace ::lestes::msg;
00020 using namespace ::lestes::backend_v2::intercode;
00021 using namespace ::lestes::md::instructions;
00022 using namespace ::lestes::md::registers;
00023 using namespace ::lestes::md::mem;
00024 using namespace ::lestes::md::types;
00025 
00026 typedef set<srp<pi_mem_factory> > mf_set__type;
00027 typedef set<ulint> id_set__type;
00028 typedef vector<ulint> id_vector__type;
00029 typedef list<srp<ge_pi> > ge_pi_list__type;
00030 typedef vector<srp<liveness_range> > liveness_rng_vector__type;
00031 typedef vector<srp<alloc_interval> > alloc_int_vector__type;
00032 typedef vector<srp<ge_operand> > ge_operand_vector__type;
00033 typedef vector<srp<ge_pi> > ge_pi_vector__type;
00034 typedef set<srp<ge_pi> > ge_pi_set__type;
00035 typedef set<srp<ge_operand_reg> > ge_op_reg_set__type;
00036 typedef map<srp<pi_mem_factory>, srp<ge_pi> > mf2ge_pi__type;
00037 typedef map<ulint, srp<alloc_interval> > reg2alloc_int__type;
00038 typedef map<ulint, srp<ge_pi> > reg2ge_pi__type;
00039 typedef map<ulint, lstring > id2lstring__type;
00040 typedef map<srp<ge_pi>, ulint> ge2reg_map__type;
00041 typedef list<srp<spillgen_group> > spillgen_group_list__type;
00042 typedef set<srp<spillgen_group> > spillgen_group_set__type;
00043 typedef set<srp<alloc_interval> > alloc_int_set__type;
00044 
00045 declare_logger(slog);
00046 initialize_logger( slog, "spillgen", backend_v2_logger );
00047 
00048 declare_logger(deplog);
00049 initialize_logger( deplog, "spillgen_deps", backend_v2_logger );
00050 
00051 
00052 /*!
00053         \brief Performs spill-code generation on a function body.
00054 */
00055 void spillgen::process() {
00056         slog << "process start\n" << eolog;
00057 
00058         move_gen = move_generator::create();
00059         
00060         //Set all available registers free.
00061         setup_registers();      
00062         
00063         //Get intervals for spillcode generation.
00064         waiting_intervals = alloc_int_vector__type::create(data_get()->alloc_ints_get());
00065         
00066         //Sort intervals by increasing start point
00067         ::std::sort(waiting_intervals->begin(),waiting_intervals->end(),alloc_int_cmp1);
00068         
00069         /*
00070                 Go through function's body and generate spill code.
00071         */
00072         ptr<ge_pi_list__type> body = data_get()->ge_body_get();
00073         
00074         /*
00075                 Code is to be inserted between current and next instruction. 
00076                 Backup pointer to the next instruction in order to not process inserted code.
00077         */
00078         ge_pi_list__type::iterator it_next;
00079         
00080         for(ge_pi_list__type::iterator it = body->begin(); it!=body->end();) {
00081                 ptr<ge_pi> ge = *it;
00082                 
00083                 it_next = it;
00084                 ++it_next;
00085                 
00086                 //Remove overaged (interval->end < ge->schedule_pos) intervals from the active set.
00087                 expire_old_intervals(ge->schedule_pos_get());
00088                 
00089                 //Activate waiting intervals (interval->start <= ge->schedule_pos)
00090                 activate_waiting_intervals(ge->schedule_pos_get());
00091                 
00092                 //Recompute free register set according to used register set.
00093                 find_free_registers();
00094                 
00095                 //Generate spill code for instruction.
00096                 process_instruction(ge,body,it); 
00097                 
00098                 it = it_next;
00099         }
00100 
00101         lassert(waiting_intervals->size()==0);
00102         
00103         slog << "process end\n" << eolog;
00104 }
00105 
00106 /*!
00107         \brief Generates spill-code for a pseudoinstruction.
00108         
00109         \param ge The pseudoinstruction.
00110         \param output An output list where any generated code is to be inserted.
00111         \param it An insert iterator.
00112 */
00113 void spillgen::process_instruction(ptr<ge_pi> ge, ptr<ge_pi_list__type> output, ge_pi_list__type::iterator it) {
00114         slog << "process_instruction start\n" << eolog;
00115         
00116         //Find operand groups that shares single register.
00117         bool b_spilling_needed = identify_groups(ge);
00118 
00119         if ( !b_spilling_needed ) {
00120                 /*No operand needs spilling. */
00121                 
00122                 //Update dependencies and last use of used registers and spill-spaces.
00123                 for(spillgen_group_list__type::iterator it = groups->begin(); it!=groups->end(); ++it) {
00124                         ptr<spillgen_group> group = *it;
00125                         
00126                         if ( group->backup_space_get() ) {
00127                                 ptr<pi_mem_factory> mf = group->backup_space_get()->factory_get();
00128                                 
00129                                 mf2ge_pi__type::iterator it_mf_last_use = spill_space_last_use->find(mf);
00130                                 if ( it_mf_last_use!=spill_space_last_use->end() ) {
00131                                         deplog << "A. " << ge->uid_get() << " -> " <<  it_mf_last_use->second->uid_get() << "\n" << eolog;
00132                                         ge->dependencies_get()->insert(it_mf_last_use->second);
00133                                 }
00134                                 
00135                                 (*spill_space_last_use)[mf] = ge;               
00136                         }       
00137                         
00138                         lassert(group->reg_get());
00139                         
00140                         ptr<ge_pi> last_use = find_last_use_of_register(group->reg_get()->id_get());
00141                         if ( last_use ) {
00142                                 deplog << "B. " << ge->uid_get() << " -> " <<  last_use->uid_get() << "\n" << eolog;
00143                                 ge->dependencies_get()->insert(last_use);
00144                         }
00145                         
00146                         set_last_use_of_register(group->reg_get()->id_get(),ge);
00147                 }       
00148                 slog << "process_instruction end 1\n" << eolog;
00149                 return;
00150         }       
00151         
00152         //Temporaly allocate spill registers for groups that has no register regular allocated.
00153         allocate_regs_for_groups();
00154         
00155         //Generate spill code (load,store) for spilled operands.
00156         generate_spill_code(ge,output,it);
00157         
00158         free_group_resources();
00159         
00160         slog << "process_instruction end\n" << eolog;
00161 }
00162 
00163 /*!
00164         \brief Frees resources (registers,spill-places) used by spill-code generation for the currently processed instruction.
00165 */
00166 void spillgen::free_group_resources() {
00167         slog << "free_group_resources start\n" << eolog;
00168         
00169         //Setup dependencies of the previously generated spill code.
00170         for(spillgen_group_list__type::iterator it = groups->begin(); it!=groups->end(); ++it) {
00171                 ptr<spillgen_group> group = *it;
00172 
00173                 if ( group->backup_space_get() ) {                      
00174                         ptr<pi_mem_factory> mf = group->backup_space_get()->factory_get();
00175         
00176                         //Free the spill place.
00177                         free_spill_spaces->insert(mf);  
00178                 }
00179         }
00180         
00181         slog << "free_group_resources end\n" << eolog;
00182 }
00183 
00184 /*!
00185         \brief Generates code that backups register used by spill-code of a group.
00186         
00187         \param ge A currently processed pseudoinstruction.
00188         \param group The group.
00189         \param reg_orig_owners A list of intervals that uses the register.
00190         \return The generated code.
00191 */
00192 ptr<ge_pi_vector__type> spillgen::generate_backup_code(ptr<ge_pi> ge,ptr<spillgen_group> group,ptr<alloc_int_set__type> reg_orig_owners) {
00193         ptr<ge_pi_vector__type> backup_code;
00194         
00195         ptr<tm_register> group_reg = group->reg_get();          
00196         
00197         lassert(group_reg);
00198         
00199         if ( reg_orig_owners->size()!=0 ) {
00200                 //The register is currently owned by another operand. It must be backed-up.
00201                 
00202                 //Datatype of the value from the preserved register.
00203                 ptr<tm_data_type_base> backup_type = tm_dt_simple::instance((dt_id_type)*group_reg->compatible_types_get()->begin());
00204                 
00205                 //Backup place.
00206                 ptr<pi_mem_factory> mf = get_free_spill_space(backup_type);
00207                 lassert(mf);
00208                 ptr<ge_operand_mem> backup_space = mf->get_ge_mem(NULL);
00209                 group->backup_space_set(backup_space);  
00210                 
00211                 //Faked operand for preserved register.
00212                 ptr<ge_operand_reg> reg_to_backup = ge_operand_reg::create(backup_type,ge->bb_get()->fsp_get(),NULL);
00213                 
00214                 backup_code = move_gen->generate_store_to_memory(reg_to_backup,group_reg,backup_space); 
00215                 
00216                 /*
00217                         The backup_code must not overlap with any code that used the spill space before.
00218                         Add dependence of the code to the preceeding code.
00219                 */
00220                 mf2ge_pi__type::iterator it_mf = spill_space_last_use->find(mf);
00221                 if ( it_mf!=spill_space_last_use->end() ) {
00222                         deplog << "C. " << backup_code->front()->uid_get() << " -> " <<  it_mf->second->uid_get() << "\n" << eolog;
00223                         backup_code->front()->dependencies_get()->insert(it_mf->second);
00224                 }
00225                                         
00226                 
00227         } else {
00228                 //The register is not used. No backup required. Just create ge_sp to make setting-up dependecies easier (the backup code always exists).
00229                 backup_code = ge_pi_vector__type::create();
00230                 backup_code->push_back(ge_sp::create(NULL,NULL));
00231                 
00232                 
00233         }
00234                 
00235         lassert(backup_code && backup_code->size()!=0);
00236         
00237         //Instruction that is previous user of the register
00238         ptr<ge_pi> reg_last_use = find_last_use_of_register(group_reg->id_get());
00239                 
00240         /*
00241                 The code must not overlap with any code that used the spill register before.
00242                 Add dependence of the code to the preceeding code.
00243         */
00244         if ( reg_last_use && curr_generated_instructions->find(reg_last_use)==curr_generated_instructions->end() ) {
00245                 deplog << "D. " << backup_code->front()->uid_get() << " -> " <<  reg_last_use->uid_get() << "\n" << eolog;
00246                 backup_code->front()->dependencies_get()->insert(reg_last_use);
00247         }
00248         
00249         group->backup_instructions_set(backup_code);
00250         
00251         //The instruction ge must be places behind the backup code.
00252         deplog << "E. " << ge->uid_get() << " -> " <<  backup_code->back()->uid_get() << "\n" << eolog;
00253         ge->dependencies_get()->insert(backup_code->back());
00254         
00255         //Copy the code to basic block of the instruction ge.
00256         insert_code_to_bb(ge->bb_get(),backup_code,false);      
00257                 
00258         return backup_code;
00259 }
00260 
00261 
00262 /*!
00263         \brief Generates code that restores register used by spill-code of a group of a pseudoinstructions.
00264         
00265         \param ge A currently processed pseudoinstruction.
00266         \param group The group.
00267         \param reg_orig_owners A list of intervals that uses the register.
00268         \return The generated code.
00269 */
00270 
00271 ptr<ge_pi_vector__type> spillgen::generate_restore_code(ptr<ge_pi> ge,ptr<spillgen_group> group,ptr<alloc_int_set__type> reg_orig_owners) {
00272         ptr<ge_pi_vector__type> restore_code;
00273         
00274         ptr<tm_register> group_reg = group->reg_get();          
00275         
00276         lassert(group_reg);
00277         
00278         if ( reg_orig_owners->size()!=0 ) {
00279                 //The register is currently owned by another operand. It must be backed-up.
00280                 ptr<ge_operand_mem> backup_space = group->backup_space_get();
00281                 
00282                 ptr<pi_mem_factory> mf = backup_space->factory_get();
00283                 lassert(mf);
00284                 
00285                 ptr<ge_operand_reg> reg_to_restore = ge_operand_reg::create(backup_space->type_get(),ge->bb_get()->fsp_get(),NULL);
00286                         
00287                 restore_code = move_gen->generate_load_from_memory(backup_space,reg_to_restore,group_reg);
00288                 
00289                 //Set restore code as last user of the spill place.
00290                 (*spill_space_last_use)[mf] = restore_code->back();             
00291         } else {
00292                 //The register is not used. No backup required. Just create ge_sp to make setting-up dependecies easyer (the backup code always exists).
00293                 restore_code = ge_pi_vector__type::create();
00294                 restore_code->push_back(ge_sp::create(NULL,NULL));
00295         }       
00296                 
00297         lassert(restore_code && restore_code->size());
00298         
00299         //Set restore code as last user of the register.
00300         set_last_use_of_register(group_reg->id_get(),restore_code->back());
00301         
00302         group->restore_instructions_set(restore_code);
00303         
00304         //Copy the code to basic block of the instruction ge.
00305         insert_code_to_bb(ge->bb_get(),restore_code,true);      
00306                         
00307         //The restore code must follows the instruction ge.
00308         deplog << "F. " << restore_code->front()->uid_get() << " -> " <<  ge->uid_get() << "\n" << eolog;
00309         restore_code->front()->dependencies_get()->insert(ge);  
00310                         
00311         return restore_code;
00312 }
00313 
00314 /*!
00315         \brief Generates code that loads value of a spilled operand from memory to a temporarly allocated register.
00316         
00317         \param ge A currently processed pseudoinstruction.
00318         \param group A group of the operand.
00319         \param interval An interval of the operand.
00320         \param operand The operand.
00321         \param reg The tmp register.
00322         \return The generated code.
00323 */
00324 ptr<ge_pi_vector__type> spillgen::generate_load_code(ptr<ge_pi> ge,ptr<spillgen_group> group,ptr<alloc_interval> interval,ptr<ge_operand_reg> operand, ptr<tm_register> reg) {
00325         lassert(reg);
00326         
00327         ptr<ge_pi_vector__type> load_code;      
00328         
00329         if ( interval->allocated_reg_get() ) {
00330                 /*
00331                         The operand's interval has register assigned. But it differs from the group's register. 
00332                         Generate copy code that copies value between these registers to get it into the right one.
00333                 */
00334                 ptr<ge_operand_reg> source_operand = ge_operand_reg::create(operand->type_get(),ge->bb_get()->fsp_get(),NULL);
00335                 load_code = move_gen->generate_copy_to_register(source_operand,interval->allocated_reg_get(),operand,reg);
00336                 
00337                 //Load code of any thief group must follows the copy code.
00338                 ptr<spillgen_group_set__type> thief_groups = find_groups_by_reg(interval->allocated_reg_get());
00339                 lassert(thief_groups->size()!=0);
00340                 
00341                 for(spillgen_group_set__type::iterator it = thief_groups->begin(); it!=thief_groups->end(); ++it) {
00342                         ptr<spillgen_group> thief = *it;
00343                         deplog << "G. " << thief->backup_instructions_get()->front()->uid_get() << " -> " <<  load_code->back()->uid_get() << "\n" << eolog;
00344                         thief->backup_instructions_get()->front()->dependencies_get()->insert(load_code->back());
00345                 }
00346         } else {
00347                 //Load value from spill-space to the register.          
00348                 ptr<pi_mem_factory> mf = interval->allocated_spill_place_get();
00349                 
00350                 if ( !mf ) {
00351                         //Spill space has not been yet assigned to the operand's interval. Do it now.
00352                         mf = get_free_spill_space(operand->type_get());
00353                         interval->allocated_spill_place_set(mf);        
00354                 }
00355                 //Load value from spill-space to the register.          
00356                 ptr<ge_operand_mem> spill_place = mf->get_ge_mem(ge->bb_get()->fsp_get());
00357                 
00358                 load_code = move_gen->generate_load_from_memory(spill_place,operand,reg);
00359         
00360                 //Setup dependencies in order to not allow the store code and previous user of the spill place overlap.
00361                 mf2ge_pi__type::iterator mf_it = spill_space_last_use->find(mf);
00362                 if ( mf_it!=spill_space_last_use->end() ) {
00363                         deplog << "H. " << load_code->front()->uid_get() << " -> " <<  mf_it->second->uid_get() << "\n" << eolog;
00364                         load_code->front()->dependencies_get()->insert(mf_it->second);
00365                 }
00366                 
00367                 //Set last user of the spill place.
00368                 (*spill_space_last_use)[mf] = load_code->back();
00369         }       
00370         
00371         lassert(load_code && load_code->size());
00372         
00373         //Set last user of the register.
00374         //set_last_use_of_register(reg->id_get(),ge);
00375         
00376         group->load_instructions_get()->insert(load_code->begin(),load_code->end());
00377         
00378         //Copy the code to basic block of the operands instruction.
00379         insert_code_to_bb(ge->bb_get(),load_code,false);        
00380         
00381         //The load code must follows the backup code. 
00382         deplog << "I. " << load_code->front()->uid_get() << " -> " <<  group->backup_instructions_get()->back()->uid_get() << "\n" << eolog;
00383         load_code->front()->dependencies_get()->insert(group->backup_instructions_get()->back());
00384                 
00385         //Previous instruction in the operand's interval.
00386         ptr<ge_pi> interval_prev_instr = interval_find_previous_instruction(interval,ge->schedule_pos_get());
00387                 
00388         if ( interval_prev_instr ) {
00389                 //Load code must follows the interval's previous instruction.
00390                 deplog << "J. " << load_code->front()->uid_get() << " -> " <<  interval_prev_instr->uid_get() << "\n" << eolog;
00391                 load_code->front()->dependencies_get()->insert(interval_prev_instr);
00392         }
00393                 
00394         //Instruction must follows load code.
00395         deplog << "K. " << ge->uid_get() << " -> " <<  load_code->back()->uid_get() << "\n" << eolog;
00396         ge->dependencies_get()->insert(load_code->back());
00397         
00398         //Finally, set register to operand within instruction.
00399         (*operand->assigned_registers_get())[ge] = reg->id_get();
00400         
00401         return load_code;
00402 }
00403 
00404 /*!
00405         \brief Generates code that store value of a spilled operand from a temporarly allocated register to a spill-place.
00406         
00407         \param ge A currently processed pseudoinstruction.
00408         \param group A group of the operand.
00409         \param interval An interval of the operand.
00410         \param operand The operand.
00411         \param reg The tmp register.
00412         \return The generated code.
00413 */
00414 ptr<ge_pi_vector__type> spillgen::generate_store_code(ptr<ge_pi> ge,ptr<spillgen_group> group,ptr<alloc_interval> interval,ptr<ge_operand_reg> operand, ptr<tm_register> reg) {
00415         lassert(reg);
00416         
00417         ptr<ge_pi_vector__type> store_code;     
00418 
00419         if ( interval->allocated_reg_get() ) {
00420                 /*
00421                         The operand's interval has register assigned. But it differs from the group's register. 
00422                         Generate copy code that copies value between these registers to get it into the right one.
00423                 */
00424                 ptr<ge_operand_reg> destination_operand = ge_operand_reg::create(operand->type_get(),NULL,NULL);
00425 
00426                 store_code = move_gen->generate_copy_to_register(operand,reg,destination_operand,interval->allocated_reg_get());
00427                 
00428                 ge->bb_get()->lsp_get()->operands_input_get()->push_back(destination_operand);
00429                 
00430                 //The copy code must follows restore of any thief group.
00431                 ptr<spillgen_group_set__type> thief_groups = find_groups_by_reg(interval->allocated_reg_get());
00432                 
00433                 for(spillgen_group_set__type::iterator it = thief_groups->begin(); it!=thief_groups->end(); ++it) {
00434                         ptr<spillgen_group> thief = *it;
00435                         deplog << "L. " << store_code->front()->uid_get() << " -> " <<  thief->restore_instructions_get()->back()->uid_get() << "\n" << eolog;
00436                         store_code->front()->dependencies_get()->insert(thief->restore_instructions_get()->back());
00437                 }
00438         } else {
00439                 ptr<pi_mem_factory> mf = interval->allocated_spill_place_get();
00440                 
00441                 if ( !mf ) {
00442                         //Spill space has not been yet assigned to the operand's interval. Do it now.
00443                         mf = get_free_spill_space(operand->type_get());
00444                         interval->allocated_spill_place_set(mf);        
00445                 }
00446                 
00447                 //Store value from spill-space to the register.         
00448                 ptr<ge_operand_mem> spill_place = mf->get_ge_mem(NULL);
00449                 store_code = move_gen->generate_store_to_memory(operand,reg,spill_place);
00450                 spill_place->origin_set(store_code->back());
00451         
00452                 //Setup dependencies in order to not allow the store code and previous user of the spill place overlap.
00453                 mf2ge_pi__type::iterator mf_it = spill_space_last_use->find(mf);
00454                 if ( mf_it!=spill_space_last_use->end() ) {
00455                         deplog << "M. " << store_code->front()->uid_get() << " -> " <<  mf_it->second->uid_get() << "\n" << eolog;
00456                         store_code->front()->dependencies_get()->insert(mf_it->second);
00457                 }
00458                 
00459                 //Set last user of the spill place.
00460                 (*spill_space_last_use)[mf] = store_code->back();
00461         }       
00462         
00463         lassert(store_code && store_code->size());
00464         
00465         //Set last user of the register.
00466         //set_last_use_of_register(reg->id_get(),store_code->back());
00467         
00468         group->store_instructions_get()->insert(store_code->begin(),store_code->end());
00469         
00470         //Copy the code to basic block of the instruction ge.
00471         insert_code_to_bb(ge->bb_get(),store_code,true);        
00472         
00473         //The store code must follows ge.
00474         deplog << "N. " << store_code->front()->uid_get() << " -> " <<  ge->uid_get() << "\n" << eolog;
00475         store_code->front()->dependencies_get()->insert(ge);
00476                 
00477         //The restore code must follows the store code.
00478         deplog << "O. " << group->restore_instructions_get()->front()->uid_get() << " -> " <<  store_code->back()->uid_get() << "\n" << eolog;
00479         group->restore_instructions_get()->front()->dependencies_get()->insert(store_code->back());
00480                 
00481         //The following instruction of the interval must follows the store code.
00482         ptr<ge_pi> interval_next_instr = interval_find_next_instruction(interval,ge->schedule_pos_get());
00483         if ( interval_next_instr ) {
00484                 deplog << "P. " << interval_next_instr->uid_get() << " -> " <<  store_code->back()->uid_get() << "\n" << eolog;
00485                 interval_next_instr->dependencies_get()->insert(store_code->back());
00486         }
00487         
00488         //Finally, set register to operand within instruction.
00489         (*operand->assigned_registers_get())[ge] = reg->id_get();
00490         
00491         return store_code;
00492 }
00493 
00494 /*!
00495         \brief Returns spillgen_groups that corresponds to a register within a currently processed instruction.
00496         
00497         \param reg The register.
00498         \return The set of groups.
00499 */
00500 ptr<spillgen_group_set__type> spillgen::find_groups_by_reg(ptr<tm_register> reg) {
00501         slog << "find_groups_by_reg start\n" << eolog;
00502         
00503         ptr<spillgen_group_set__type> found_groups = spillgen_group_set__type::create();
00504         
00505         ptr<id_set__type> aliases = reg->aliases_get();
00506         
00507         for(spillgen_group_list__type::iterator it = groups->begin(); it!=groups->end(); ++it) {
00508                 ptr<spillgen_group> group = *it;
00509                         
00510                 //Register used by the group.
00511                 ptr<tm_register> group_reg = group->reg_get();          
00512                 
00513                 if ( aliases->find(group_reg->id_get())!=aliases->end() ) {
00514                         found_groups->insert(group);
00515                 }
00516         }
00517         
00518         slog << "find_groups_by_reg end\n" << eolog;
00519         
00520         return found_groups;
00521 }
00522 
00523 /*!
00524         \brief Generates code for a pseudoinstruction.
00525         
00526         \param ge The pseudoinstruction.
00527         \param output An output list where any generated code is to be inserted.
00528         \param it An insert iterator.
00529 */
00530 void spillgen::generate_spill_code(ptr<ge_pi> ge,ptr<ge_pi_list__type>, ge_pi_list__type::iterator) {
00531         slog << "generate_spill_code start\n" << eolog;
00532         
00533         slog << "generate_spill_code for ge_pi=" << ge->uid_get() << "\n" << eolog;
00534         
00535         curr_generated_instructions->clear();
00536         
00537         //Generate backup and restore code.
00538         for(spillgen_group_list__type::iterator it = groups->begin(); it!=groups->end(); ++it) {
00539                 ptr<spillgen_group> group = *it;
00540                         
00541                 //Register used by the group.
00542                 ptr<tm_register> group_reg = group->reg_get();          
00543                 lassert(group_reg);
00544                 
00545                 if ( group_reg->is_unspillable() ) {
00546                         ptr<ge_op_reg_set__type> operands = group->operands_get();
00547                         for(ge_op_reg_set__type::iterator it2 = operands->begin(); it2!=operands->end(); ++it2) {
00548                                 (*(*it2)->assigned_registers_get())[ge] = group_reg->id_get();
00549                         }
00550                         continue;
00551                 }
00552                 
00553                 //Registers that will be divided among group's operands.
00554                 group->avail_regs_for_input_ops_set(id_set__type::create(group_reg->aliases_get()));
00555                 group->avail_regs_for_output_ops_set(id_set__type::create(group_reg->aliases_get()));
00556                 
00557                 //Owners (intervals that have the register (or its parts) allocated.            
00558                 ptr<alloc_int_set__type> orig_owners = find_register_owners(group_reg);
00559                 
00560                 //Remove intervals of the group's operands from orig_owners set.
00561                 for(spillgen_group_list__type::iterator it1 = groups->begin(); it1!=groups->end(); ++it1) {
00562                         
00563                         ptr<ge_op_reg_set__type> operands = (*it1)->operands_get();
00564                         
00565                         for(ge_op_reg_set__type::iterator it2 = operands->begin(); it2!=operands->end(); ++it2) {
00566                                 ptr<alloc_interval> interval = (*op2interval)[*it2];
00567                                 orig_owners->erase(interval);
00568                         }
00569                 }       
00570                 
00571                 //The register contains active data that has to be preserved. Backup it.
00572                 ptr<ge_pi_vector__type> backup_code = generate_backup_code(ge, group, orig_owners);
00573                 
00574                 curr_generated_instructions->insert(backup_code->begin(),backup_code->end());
00575                 
00576 #ifdef BACKEND_V2_DEBUG         
00577                 ::std::ostringstream oss1;
00578                 oss1 << "backup code (ge_pi=" << ge->uid_get() << ", group=" << group->uid_get() << ")";
00579                 set_instruction_property(backup_code,ge_pi::PROPERTY_SPILLGEN_INFO,oss1.str());
00580 #endif
00581                 
00582                 //Restore original value.
00583                 ptr<ge_pi_vector__type> restore_code = generate_restore_code(ge, group, orig_owners);
00584 
00585                 curr_generated_instructions->insert(restore_code->begin(),restore_code->end());
00586                 
00587 #ifdef BACKEND_V2_DEBUG         
00588                 ::std::ostringstream oss2;
00589                 oss2 << "restore code (ge_pi=" << ge->uid_get() << ", group=" << group->uid_get() << ")";
00590                 set_instruction_property(restore_code,ge_pi::PROPERTY_SPILLGEN_INFO,oss2.str());
00591 #endif
00592                 
00593         }
00594         
00595         /* Generate load and store code. */
00596         ulint op_pos = 0;
00597         ptr<ge_operand_vector__type> ops = ge->operands_input_get();
00598         for(ge_operand_vector__type::iterator it = ops->begin(); it!=ops->end(); ++it, ++op_pos) {
00599         
00600                 if ( (*it)->kind_get()!=ge_operand::REGISTER ) {
00601                         continue;
00602                 }
00603                 
00604                 ptr<ge_operand_reg> op = (*it).dncast<ge_operand_reg>();
00605                 ptr<tm_instr_op_reg> tmop = (*ge->instruction_get()->operands_input_get())[op_pos].dncast<tm_instr_op_reg>();
00606                 
00607                 ptr<spillgen_group> group = (*op2group)[op];
00608                 lassert(group);
00609                 
00610                 ptr<alloc_interval> interval = (*op2interval)[op];
00611                 lassert(interval);
00612                 
00613                 //Register used by the group.
00614                 ptr<tm_register> group_reg = group->reg_get();          
00615                 lassert(group_reg);
00616                 
00617                 if ( group_reg->is_unspillable() ) {
00618                         continue;
00619                 }
00620                 
00621                 ptr<id_set__type> tmp_set = id_set__type::create();
00622                 
00623                 ::std::set_intersection(
00624                         group->avail_regs_for_input_ops_get()->begin(),
00625                         group->avail_regs_for_input_ops_get()->end(),
00626                         tmop->allowed_registers_get()->begin(),
00627                         tmop->allowed_registers_get()->end(),
00628                         ::std::inserter(*tmp_set,tmp_set->begin()));
00629                         
00630                 lassert(tmp_set->size()!=0);
00631                 
00632                 tmp_set = filter_regs_by_data_type(tmp_set,op->type_get()->id_get());
00633                 
00634                 //Register used by the operand.
00635                 ptr<tm_register> interval_reg = tm_register::instance(*tmp_set->begin());
00636                 
00637                 //Update set of available registers.
00638                 tmp_set = id_set__type::create();
00639                 ::std::set_difference(
00640                         group->avail_regs_for_input_ops_get()->begin(),
00641                         group->avail_regs_for_input_ops_get()->end(),
00642                         interval_reg->aliases_get()->begin(),
00643                         interval_reg->aliases_get()->end(),
00644                         ::std::inserter(*tmp_set,tmp_set->begin()));
00645                         
00646                 group->avail_regs_for_input_ops_set(tmp_set);
00647                 
00648                 if ( interval->allocated_reg_get()==interval_reg ) {
00649                         //Owner of the register is operand's interval itsef.
00650                         continue;
00651                 }
00652 
00653                 //Generate load of the spilled operand's value.
00654                 ptr<ge_pi_vector__type> load_code = generate_load_code(ge,group,interval,op,interval_reg);
00655                 
00656                 curr_generated_instructions->insert(load_code->begin(),load_code->end());
00657                 
00658 #ifdef BACKEND_V2_DEBUG         
00659                 ::std::ostringstream oss1;
00660                 oss1 << "load code (ge_pi=" << ge->uid_get() << ", group=" << group->uid_get() << ", interval=" << interval->uid_get() << ")";
00661                 set_instruction_property(load_code,ge_pi::PROPERTY_SPILLGEN_INFO,oss1.str());
00662 #endif
00663 
00664         }
00665         
00666         op_pos = 0;
00667         ops = ge->operands_output_get();
00668         for(ge_operand_vector__type::iterator it = ops->begin(); it!=ops->end(); ++it, ++op_pos) {
00669         
00670                 if ( (*it)->kind_get()!=ge_operand::REGISTER ) {
00671                         continue;
00672                 }
00673                 
00674                 ptr<ge_operand_reg> op = (*it).dncast<ge_operand_reg>();
00675                 ptr<tm_instr_op_reg> tmop = (*ge->instruction_get()->operands_output_get())[op_pos].dncast<tm_instr_op_reg>();
00676                 
00677                 ptr<spillgen_group> group = (*op2group)[op];
00678                 lassert(group);
00679                 
00680                 ptr<alloc_interval> interval = (*op2interval)[op];
00681                 lassert(interval);
00682                 
00683                 //Register used by the group.
00684                 ptr<tm_register> group_reg = group->reg_get();          
00685                 lassert(group_reg);
00686                 
00687                 if ( group_reg->is_unspillable() ) {
00688                         continue;
00689                 }
00690                 
00691                 ptr<id_set__type> tmp_set = id_set__type::create();
00692                 
00693                 ::std::set_intersection(
00694                         group->avail_regs_for_output_ops_get()->begin(),
00695                         group->avail_regs_for_output_ops_get()->end(),
00696                         tmop->allowed_registers_get()->begin(),
00697                         tmop->allowed_registers_get()->end(),
00698                         ::std::inserter(*tmp_set,tmp_set->begin()));
00699         
00700                 tmp_set = filter_regs_by_data_type(tmp_set,op->type_get()->id_get());
00701         
00702                 lassert(tmp_set->size()!=0);
00703                 
00704                 //Register used by the operand.
00705                 ptr<tm_register> interval_reg = tm_register::instance(*tmp_set->begin());
00706                 
00707                 //Update set of available registers.
00708                 tmp_set = id_set__type::create();
00709                 ::std::set_difference(
00710                         group->avail_regs_for_output_ops_get()->begin(),
00711                         group->avail_regs_for_output_ops_get()->end(),
00712                         interval_reg->aliases_get()->begin(),
00713                         interval_reg->aliases_get()->end(),
00714                         ::std::inserter(*tmp_set,tmp_set->begin()));
00715                         
00716                 group->avail_regs_for_output_ops_set(tmp_set);
00717                 
00718                 if ( interval->allocated_reg_get()==interval_reg ) {
00719                         //Owner of the register is operand's interval itsef.
00720                         continue;
00721                 }
00722 
00723                 //Generate store of the spilled operand's value.
00724                 ptr<ge_pi_vector__type> store_code = generate_store_code(ge,group,interval,op,interval_reg);
00725 
00726                 curr_generated_instructions->insert(store_code->begin(),store_code->end());
00727                 
00728 #ifdef BACKEND_V2_DEBUG         
00729                 ::std::ostringstream oss1;
00730                 oss1 << "store code (ge_pi=" << ge->uid_get() << ", group=" << group->uid_get() << ", interval=" << interval->uid_get() << ")";
00731                 set_instruction_property(store_code,ge_pi::PROPERTY_SPILLGEN_INFO,oss1.str());
00732 #endif
00733                 
00734         }
00735         
00736         slog << "generate_spill_code end\n" << eolog;
00737 }
00738 
00739 /*!
00740         \brief Finds an instruction that precedes given position within an interval.
00741         
00742         \param interval The interval.
00743         \param curr_pos The position.
00744         \return The previous instruction.
00745 */
00746 ptr<ge_pi> spillgen::interval_find_previous_instruction(ptr<alloc_interval> interval, ulint curr_pos) {
00747         slog << "interval_find_previous_instruction start\n" << eolog;
00748         
00749         ptr<ge_pi_vector__type> instructions = interval->instructions_get();
00750         
00751         for(ge_pi_vector__type::reverse_iterator it = instructions->rbegin(); it!=instructions->rend(); ++it) {
00752                 if ( (*it)->schedule_pos_get() < curr_pos ) {
00753                         slog << "interval_find_revious_instruction end 1\n" << eolog;
00754                         return *it;
00755                 }
00756         }       
00757         
00758         slog << "interval_find_previous_instruction end\n" << eolog;
00759         
00760         return NULL;
00761 }
00762 
00763 /*!
00764         \brief Finds an instruction that follows given position within an interval.
00765         
00766         \param interval The interval.
00767         \param curr_pos The position.
00768         \return The following instruction.
00769 */
00770 ptr<ge_pi> spillgen::interval_find_next_instruction(ptr<alloc_interval> interval, ulint curr_pos) {
00771         slog << "interval_find_next_instruction start\n" << eolog;
00772         
00773         ptr<ge_pi_vector__type> instructions = interval->instructions_get();
00774         
00775         for(ge_pi_vector__type::iterator it = instructions->begin(); it!=instructions->end(); ++it) {
00776                 if ( (*it)->schedule_pos_get() > curr_pos ) {
00777                         slog << "interval_find_next_instruction end 1\n" << eolog;
00778                         return *it;
00779                 }
00780         }       
00781         
00782         slog << "interval_find_next_instruction end\n" << eolog;
00783         
00784         return NULL;
00785 }
00786 
00787 /*!
00788         \brief Searches for intervals that currently use a register ( or its aliases ).
00789         
00790         \param reg The register.
00791         \return A set of intervals.
00792 */
00793 ptr<alloc_int_set__type> spillgen::find_register_owners(ptr<tm_register> reg) {
00794         slog << "find_register_owners start\n" << eolog;
00795         
00796         ptr<alloc_int_set__type> res = alloc_int_set__type::create();
00797         
00798         ptr<id_set__type> aliases = reg->aliases_get();
00799         
00800         for(id_set__type::iterator it = aliases->begin(); it!=aliases->end(); ++it) {
00801                 reg2alloc_int__type::iterator it_int = register_owners->find(*it);
00802                 
00803                 if ( it_int!=register_owners->end() ) {
00804                         res->insert(it_int->second);
00805                 }
00806         }
00807         
00808         slog << "find_register_owners end\n" << eolog;
00809         return res;
00810 }
00811 
00812 /*!
00813         \brief Allocates registers to operand groups of a currently processed instruction.
00814 */
00815 void spillgen::allocate_regs_for_groups() {
00816         slog << "allocate_regs_for_groups start\n" << eolog;    
00817         
00818         spillgen_group_list__type::iterator it_stop = groups->end();
00819         spillgen_group_list__type::iterator it = groups->begin();
00820         
00821         while (true) {
00822                 if ( it_stop==it ) {
00823                         break;
00824                 }
00825                 
00826                 if ( it == groups->end() ) {
00827                         it = groups->begin();
00828                         continue;
00829                 }
00830                 
00831                 ptr<spillgen_group> group = *it;
00832                 
00833                 if ( !group->reg_get() ) {
00834                         allocate_reg_for_group(group);
00835                         it_stop = it;
00836                 }
00837                 
00838                 ++it;
00839         }
00840         
00841         slog << "allocate_regs_for_groups end\n" << eolog;      
00842 }
00843 
00844 /*!
00845         \brief Allocates register to a operand group of a currently processed instruction.
00846         
00847         \param group The group.
00848 */
00849 void spillgen::allocate_reg_for_group(ptr<spillgen_group> group) {
00850         slog << "allocate_reg_for_group start\n" << eolog;      
00851         
00852         ptr<id_set__type> allowed_regs =  group->allowed_registers_get();
00853         ptr<id_set__type> avail_regs = id_set__type::create();
00854         
00855         ptr<tm_register> reg;
00856         
00857         while (true) {
00858                 ptr<id_set__type> avail_regs = id_set__type::create();
00859                 
00860                 //Try find available allowed registers first.
00861                 ::std::set_intersection(
00862                         free_registers->begin(),
00863                         free_registers->end(),
00864                         allowed_regs->begin(),
00865                         allowed_regs->end(),
00866                         ::std::inserter(*avail_regs, avail_regs->begin()));
00867                         
00868 
00869                 if ( avail_regs->size()==0 ) {
00870                         /*
00871                                 No free allowed register found.
00872                                 Try steal a register from operand not used within this ge_pi.
00873                         */
00874                         ptr<id_set__type> tmp = id_set__type::create();
00875                 
00876                         ::std::set_difference(
00877                                 all_registers->begin(),
00878                                 all_registers->end(),
00879                                 regs_used_by_groups->begin(),
00880                                 regs_used_by_groups->end(),
00881                                 ::std::inserter(*tmp, tmp->begin()));
00882                         
00883                         ::std::set_intersection(
00884                                 tmp->begin(),
00885                                 tmp->end(),
00886                                 allowed_regs->begin(),
00887                                 allowed_regs->end(),
00888                                 ::std::inserter(*avail_regs, avail_regs->begin()));
00889                         
00890                 }
00891                         
00892                 if ( avail_regs->size()!=0 ) {
00893                         reg = tm_register::instance(*avail_regs->begin());      
00894                         break;
00895                 }        
00896         
00897                 //No free or stolen one available. Steal one from an operand within the same ge_pi.
00898                 steal_register_from_siblings(group, allowed_regs);
00899         }
00900                 
00901         lassert(reg);
00902         lassert(allowed_regs->find(reg->id_get())!=allowed_regs->end());
00903         
00904         group->reg_set(reg);
00905         
00906         regs_used_by_groups->insert(reg->aliases_get()->begin(),reg->aliases_get()->end());
00907         
00908         ptr<id_set__type> updated_free_registers = id_set__type::create();
00909         
00910         ::std::set_difference(
00911                         all_registers->begin(),
00912                         all_registers->end(),
00913                         reg->aliases_get()->begin(),
00914                         reg->aliases_get()->end(),
00915                         ::std::inserter(*updated_free_registers,updated_free_registers->begin()));
00916                         
00917         free_registers = updated_free_registers;
00918         
00919         slog << "allocate_reg_for_group end\n" << eolog;        
00920 }
00921 
00922 /*!
00923         \brief Finds a group of groups of a currently processed instruction that uses one of allowed registers and steals its register.
00924         \param A group that needs a register.
00925         \param allowed_regs The set of allowed registers.
00926 */
00927 void spillgen::steal_register_from_siblings(ptr<spillgen_group> thief, ptr<id_set__type> allowed_regs) {
00928         slog << "steal_register_from_siblings start\n" << eolog;        
00929         
00930         ptr<spillgen_group> guarded_grp = thief->guarded_group_get();
00931         
00932         for(spillgen_group_list__type::iterator it = groups->begin(); it!=groups->end(); ++it) {
00933                 ptr<spillgen_group> group = *it;
00934                 
00935                 if ( group!=thief && group!=guarded_grp && group->reg_get() && group->allowed_registers_get()->size()>1 ) {
00936                         ptr<tm_register> grp_reg = group->reg_get();    
00937                         ptr<id_set__type> aliases = grp_reg->aliases_get();
00938                         
00939                         ptr<id_set__type> tmp = id_set__type::create();
00940                         
00941                         ::std::set_intersection(
00942                                 allowed_regs->begin(),
00943                                 allowed_regs->end(),
00944                                 aliases->begin(),
00945                                 aliases->end(),
00946                                 ::std::inserter(*tmp, tmp->begin()));           
00947                                 
00948                         if ( tmp->size()>0 ) {
00949                                 group->guarded_group_set(thief);
00950                                 
00951                                 free_registers->insert(aliases->begin(),aliases->end());
00952                                 
00953                                 ptr<id_set__type> tmp_set = id_set__type::create();
00954                                 ::std::set_difference(
00955                                         regs_used_by_groups->begin(),
00956                                         regs_used_by_groups->end(),
00957                                         aliases->begin(),
00958                                         aliases->end(),
00959                                         ::std::inserter(*tmp_set, tmp_set->begin()));           
00960                                         
00961                                 regs_used_by_groups = tmp_set;
00962                         }       
00963                 }
00964         }
00965         
00966         slog << "steal_register_from_siblings end\n" << eolog;  
00967 }
00968 
00969 
00970 /*!
00971         \brief Groups operands of a pseudoinstruction into groups that use the same register.
00972         
00973         \param ge The pseudoinstruction.
00974         \return If a group without an allocated register has been found, it returns true. False otherwise.
00975 */
00976 bool spillgen::identify_groups(ptr<ge_pi> ge) {
00977         slog << "identify_groups start\n" << eolog;     
00978         
00979         ptr<tm_instr_base> tm = ge->instruction_get();
00980 
00981         regs_used_by_groups->clear();
00982         groups->clear();
00983         op2group->clear();
00984         
00985         if ( !tm ) {
00986                 slog << "identify_groups end 1\n" << eolog;     
00987                 return false;
00988         }       
00989         
00990         /*
00991                 Spillgen_group represents group of register operands of a single ge_pi that share a register.
00992         */
00993         bool b_nothing_to_do = true;
00994         
00995         ptr<ge_operand_vector__type> ops = ge->operands_input_get();
00996         
00997         ulint op_pos = 0;
00998         for(ge_operand_vector__type::iterator it = ops->begin(); it!=ops->end(); ++it, ++op_pos) {
00999         
01000                 if ( (*it)->kind_get()!=ge_operand::REGISTER ) {
01001                         continue;
01002                 }
01003                 
01004                 ptr<ge_operand_reg>  op = (*it).dncast<ge_operand_reg>();
01005                 ptr<tm_instr_op_reg_base> tmop = (*tm->operands_input_get())[op_pos].dncast<tm_instr_op_reg_base>();
01006                 ptr<tm_register> reg = NULL;
01007                 
01008                 ge2reg_map__type::iterator it1 = op->assigned_registers_get()->find(ge);                        
01009                 if ( it1!=op->assigned_registers_get()->end() ) {
01010                         reg = tm_register::instance(it1->second);       
01011                 } else {
01012                         b_nothing_to_do = false;
01013                 }
01014                 
01015                 ptr<spillgen_group> group = spillgen_group::create();
01016                 group->reg_set(reg);
01017                 group->operands_get()->insert(op);
01018                 group->allowed_registers_set(filter_regs_by_data_type(id_set__type::create(tmop->allowed_registers_get()), op->type_get()->id_get()));
01019                 group->is_input_set(true);
01020                 
01021                 if (reg && group->allowed_registers_get()->find(reg->id_get())==group->allowed_registers_get()->end()) {
01022                         lassert(!reg || group->allowed_registers_get()->find(reg->id_get())!=group->allowed_registers_get()->end());
01023                 }
01024                 
01025                 groups->push_back(group);
01026                 (*op2group)[op] = group;                        
01027         }
01028         
01029         ops = ge->operands_output_get();
01030         
01031         op_pos = 0;
01032         for(ge_operand_vector__type::iterator it = ops->begin(); it!=ops->end(); ++it, ++op_pos) {
01033         
01034                 if ( (*it)->kind_get()!=ge_operand::REGISTER ) {
01035                         continue;
01036                 }
01037                 
01038                 ptr<ge_operand_reg>  op = (*it).dncast<ge_operand_reg>();
01039                 ptr<tm_instr_op_reg_base> tmop = (*tm->operands_output_get())[op_pos].dncast<tm_instr_op_reg_base>();
01040                 ptr<tm_register> reg = NULL;
01041                 
01042                 ge2reg_map__type::iterator it1 = op->assigned_registers_get()->find(ge);                        
01043                 if ( it1!=op->assigned_registers_get()->end() ) {
01044                         reg = tm_register::instance(it1->second);       
01045                 } else {
01046                         b_nothing_to_do = false;
01047                 }
01048                 
01049                 ptr<spillgen_group> group;
01050                 
01051                 if ( tmop->destroys_get()==NO_OPERAND_ID ) {
01052                         //Operand doesn't destroy any input operand.
01053                         group = spillgen_group::create();
01054                         group->reg_set(reg);
01055                         group->allowed_registers_set(filter_regs_by_data_type(id_set__type::create(tmop->allowed_registers_get()), op->type_get()->id_get()));
01056                         groups->push_back(group);
01057                         
01058                         lassert(!reg || group->allowed_registers_get()->find(reg->id_get())!=group->allowed_registers_get()->end());
01059                 } else {
01060                         //Operand destroys an input operand. Insert it to the destroyed register's group.
01061                         ptr<ge_operand_reg> destroyed_op = (*ge->operands_input_get())[tmop->destroys_get() - I_1].dncast<ge_operand_reg>();
01062                         group = (*op2group)[destroyed_op];
01063                         ptr<tm_register> destroyed_reg = group->reg_get();
01064                         
01065                         if ( op->type_get()->bitwidth_get() > destroyed_op->type_get()->bitwidth_get() ) {
01066                                 group->reg_set(reg);
01067                                 
01068                                 //Free registers used by destroyed_reg within ge_pi
01069                                 if ( destroyed_reg ) {
01070                                         ptr<id_set__type> regs_to_free;
01071                                 
01072                                         if ( !reg ) {
01073                                                 //Set register used by destroyed operand free.  
01074                                                 regs_to_free =  destroyed_reg->aliases_get();
01075                                         } else {
01076                                                 //Set register used by destroyed and not used by destroyer operand free.        
01077                                                 regs_to_free = id_set__type::create();
01078                                                         
01079                                                 ::std::set_difference(
01080                                                         reg->aliases_get()->begin(),
01081                                                         reg->aliases_get()->end(),
01082                                                         destroyed_reg->aliases_get()->begin(),
01083                                                         destroyed_reg->aliases_get()->end(),
01084                                                         ::std::inserter(*regs_to_free,regs_to_free->begin()));
01085                                                 
01086                                         }
01087                         
01088                                         if ( regs_to_free ) {
01089                                                 //Update free registers.
01090                                                 free_registers->insert(regs_to_free->begin(),regs_to_free->end());
01091                                         }
01092                                 }
01093                                 
01094                                 //Update allowed register set for the group.
01095                                 group->allowed_registers_set(filter_regs_by_data_type(id_set__type::create(tmop->allowed_registers_get()),op->type_get()->id_get()));
01096                                 
01097                                 lassert(!reg || group->allowed_registers_get()->find(reg->id_get())!=group->allowed_registers_get()->end());
01098                         }
01099                 }
01100                 
01101                 group->is_output_set(true);
01102                 group->operands_get()->insert(op);
01103                 (*op2group)[op] = group;                        
01104         }
01105         
01106         //Sweep registers used by active groups.
01107         for(spillgen_group_list__type::iterator it = groups->begin(); it!=groups->end(); ++it) {
01108                 ptr<spillgen_group> group = *it;
01109                 
01110                 if ( group->reg_get() ) {
01111                         ptr<id_set__type> aliases = group->reg_get()->aliases_get();
01112                         regs_used_by_groups->insert(aliases->begin(),aliases->end());
01113                 }
01114         }
01115         
01116         slog << "find_spillgen_groups end\n" << eolog;  
01117 
01118         return !b_nothing_to_do;
01119 }
01120 
01121 /*!
01122         \brief Filters a set of registers and returns subset that can hold value of a given type.
01123         \param reg_set The source set.
01124         \param type_id The type.
01125         \return The filtered set.
01126 */
01127 ptr<id_set__type> spillgen::filter_regs_by_data_type(ptr<id_set__type> reg_set, ulint type_id) {
01128         slog << "filter_regs_by_data_type start\n" << eolog;    
01129         
01130         for(id_set__type::iterator it = reg_set->begin(); it!=reg_set->end();) {
01131                 ptr<tm_register> reg =  tm_register::instance(*it);
01132                 
01133                 if ( reg->compatible_types_get()->find(type_id)==reg->compatible_types_get()->end() ) {
01134                         id_set__type::iterator del_it = it++;
01135                         reg_set->erase(del_it);
01136                 } else {
01137                         ++it;
01138                 }
01139         }
01140         
01141         slog << "filter_regs_by_data_type end\n" << eolog;      
01142         
01143         return reg_set;
01144 }
01145 
01146 
01147 /*!
01148         \brief Fills the all_registers set with all the available registers.
01149 */
01150 void spillgen::setup_registers() {
01151         for(ulint i = R_UNDEFINED+1; i<RIT_TERMINATOR; ++i) {
01152                 all_registers->insert(i);
01153         }
01154 }
01155 
01156 /*!
01157         \brief Recomputes the free_registers set.
01158         
01159         free_registers <- all_registers - used_registers
01160 */
01161 void spillgen::find_free_registers() {
01162         slog << "find_free_registers start\n" << eolog;
01163         
01164         registers_freed = false;
01165         
01166         ptr<id_set__type> deep_used_registers = id_set__type::create();
01167         
01168         for(id_set__type::iterator it=used_registers->begin(); it!=used_registers->end(); ++it) {
01169                 ptr<tm_register> reg = tm_register::instance(*it);
01170                 
01171                 ptr<id_set__type> new_deep_used_registers = id_set__type::create();
01172                 
01173                 ::std::set_union(
01174                         reg->aliases_get()->begin(),
01175                         reg->aliases_get()->end(),
01176                         deep_used_registers->begin(),
01177                         deep_used_registers->end(),
01178                         ::std::inserter(*new_deep_used_registers,new_deep_used_registers->begin()));
01179                         
01180                 deep_used_registers = new_deep_used_registers;
01181         }
01182         
01183         ptr<id_set__type> updated_free_registers = id_set__type::create();
01184         
01185         ::std::set_difference(
01186                         all_registers->begin(),
01187                         all_registers->end(),
01188                         deep_used_registers->begin(),
01189                         deep_used_registers->end(),
01190                         ::std::inserter(*updated_free_registers,updated_free_registers->begin()));
01191                         
01192         free_registers = updated_free_registers;
01193         
01194         slog << "find_free_registers end\n" << eolog;
01195 }
01196 
01197 
01198 /*!
01199         \brief Picks a spill-place from a list of free spill-places that is compatible with a data type.
01200         
01201         If no free spill-pace is available then it allocates a new one.
01202         
01203         \param mfs The list of free spill-places.
01204         \param type The data type.
01205         \return The spill-place.
01206 */
01207 ptr<pi_mem_factory> spillgen::get_free_spill_space(ptr<tm_data_type_base> type) {
01208         slog << "get_free_spill_space start\n" << eolog;
01209         
01210         ulint bitwidth = type->bitwidth_get();
01211         
01212         /*
01213                 Find a free allocated spill space with the right bitwidth.
01214         */
01215         for(mf_set__type::iterator it = free_spill_spaces->begin(); it!=free_spill_spaces->end(); ++it) {
01216                 ptr<pi_mem_factory> mf = *it;
01217                 lassert(mf);
01218                 
01219                 if ( mf->type_get()->bitwidth_get()==bitwidth ) {
01220                         free_spill_spaces->erase(mf);
01221                         slog << "get_free_spill_space end 1\n" << eolog;
01222                         mf->type_set(type);
01223                         return mf;
01224                 }
01225         }
01226         
01227         // Free spill space has not been found. Allocate new one.
01228         ptr<pi_mem_factory> spill_space = mem_alloc_manager::instance()->allocate_local_tmp(data_get()->function_decl_get(),type);
01229         
01230         lassert(spill_space);
01231         
01232         slog << "get_free_spill_space end\n" << eolog;
01233         return spill_space;
01234 }
01235 
01236 /*!
01237         \brief Adds intervals whoose startpoints follows a currently processed point to the active_intervals set.
01238         
01239         \param curr_point The current point.
01240         \return True if an interval has been added. False otherwise.
01241 */
01242 bool spillgen::activate_waiting_intervals(ulint curr_point) {
01243         slog << "activate_waiting_intervals start\n" << eolog;
01244         
01245         bool b_free_regs_need_recalculate = false;
01246         
01247         for(alloc_int_vector__type::iterator it = waiting_intervals->begin(); it!=waiting_intervals->end();) {
01248                 ptr<alloc_interval> interval = *it;
01249                 
01250                 if ( interval->start_get() <= curr_point ) {
01251                         slog << "interval(id:" << interval->uid_get() << ") activated\n" << eolog;
01252                         
01253                         active_intervals->push_back(interval);
01254                         it = waiting_intervals->erase(it);
01255                         
01256                         ptr<tm_register> allocated_reg = interval->allocated_reg_get();
01257                         
01258                         if ( allocated_reg ) {
01259                                 (*register_owners)[allocated_reg->id_get()] = interval;
01260                                 used_registers->insert(allocated_reg->id_get());
01261                                 b_free_regs_need_recalculate = true;
01262                         }
01263                         
01264                         (*op2interval)[interval->operand_get()] = interval;
01265                 } else {
01266                         break;
01267                 }
01268         }
01269         
01270         slog << "activate_waiting_intervals end\n" << eolog;
01271         
01272         return b_free_regs_need_recalculate;
01273         
01274 }
01275 
01276 /*!
01277         \brief Removes intervals whoose endpoints precede a currently processed point from the active_intervals set.
01278         
01279         \param curr_point The current point.
01280         \return True if an interval has expired. False otherwise.
01281 */
01282 bool spillgen::expire_old_intervals(ulint curr_point) {
01283         slog << "expire_old_intervals start\n" << eolog;
01284         
01285         bool b_free_regs_need_recalculate = false;
01286         
01287         for(alloc_int_vector__type::iterator it = active_intervals->begin(); it!=active_intervals->end();) {
01288                 ptr<alloc_interval> interval = *it;
01289                 
01290                 if ( interval->end_get() < curr_point ) {
01291                         slog << "interval(id:" << interval->uid_get() << ") expired\n" << eolog;
01292                         
01293                         it = active_intervals->erase(it);                       
01294                         expired_intervals->push_back(interval);
01295                         
01296                         if ( interval->next_get() ) {
01297                                 //Copy operand's value between intervals.
01298                                 ptr<alloc_interval> next = interval->next_get();
01299                                 
01300                                 ptr<tm_register> source_reg = interval->allocated_reg_get();
01301                                 ptr<tm_register> target_reg = next->allocated_reg_get();
01302                                 
01303                                 if ( interval->allocated_spill_place_get() && !target_reg ) {
01304                                         //Reuse spill space in next interval. No copy needed.
01305                                         next->allocated_spill_place_set(interval->allocated_spill_place_get());
01306                                 } else {
01307                                         //Free spill space.
01308                                         free_spill_spaces->insert(interval->allocated_spill_place_get());
01309                                 }
01310                                 
01311                                 ptr<ge_pi_vector__type> copy_code;
01312                                 
01313                                 if ( source_reg && target_reg ) {
01314                                         //Copy value reg -> reg.
01315                                         ptr<ge_operand_reg> target_operand = ge_operand_reg::create(next->operand_get()->type_get(),NULL,NULL);
01316                                         copy_code = move_gen->generate_copy_to_register(interval->operand_get(),source_reg,target_operand,target_reg);
01317                                         target_operand->origin_set(copy_code->back());
01318                                         
01319                                         ptr<ge_pi> prev_use = find_last_use_of_register(source_reg->id_get());
01320                                         if ( prev_use ) {
01321                                                 deplog << "Q. " << copy_code->front()->uid_get() << " -> " <<  prev_use->uid_get() << "\n" << eolog;
01322                                                 copy_code->front()->dependencies_get()->insert(prev_use);
01323                                         }
01324                                         
01325                                         prev_use = find_last_use_of_register(target_reg->id_get());
01326                                         if ( prev_use ) {
01327                                                 deplog << "R. " << copy_code->front()->uid_get() << " -> " <<  prev_use->uid_get() << "\n" << eolog;
01328                                                 copy_code->front()->dependencies_get()->insert(prev_use);
01329                                         }
01330                                         
01331                                         set_last_use_of_register(source_reg->id_get(),copy_code->back());
01332                                         set_last_use_of_register(target_reg->id_get(),copy_code->back());
01333                                         
01334                                 } else if ( !source_reg && target_reg ) {
01335                                         //Copy value mem -> reg.
01336                                         ptr<pi_mem_factory> mf = interval->allocated_spill_place_get();
01337                                         ptr<ge_operand_reg> target_operand = ge_operand_reg::create(next->operand_get()->type_get(),NULL,NULL);
01338                                         ptr<ge_operand_mem> spill_place = mf->get_ge_mem(interval->instructions_get()->front());
01339                                         copy_code = move_gen->generate_load_from_memory(spill_place,target_operand,target_reg);
01340                                         target_operand->origin_set(copy_code->back());
01341                                         
01342                                         mf2ge_pi__type::iterator mf_it = spill_space_last_use->find(mf);
01343                                         if ( mf_it!=spill_space_last_use->end() ) {
01344                                                 deplog << "S. " << copy_code->front()->uid_get() << " -> " <<  mf_it->second->uid_get() << "\n" << eolog;
01345                                                 copy_code->front()->dependencies_get()->insert(mf_it->second);
01346                                         }
01347                                         
01348                                         ptr<ge_pi> prev_use = find_last_use_of_register(target_reg->id_get());
01349                                         if ( prev_use ) {
01350                                                 deplog << "T. " << copy_code->front()->uid_get() << " -> " <<  prev_use->uid_get() << "\n" << eolog;
01351                                                 copy_code->front()->dependencies_get()->insert(prev_use);
01352                                         }
01353                 
01354                                         set_last_use_of_register(target_reg->id_get(),copy_code->back());
01355                                         (*spill_space_last_use)[mf] = copy_code->back();
01356                                 } else if ( source_reg && !target_reg ) {
01357                                         //Copy value reg -> mem.
01358                                         ptr<pi_mem_factory> mf = next->allocated_spill_place_get();
01359                                         
01360                                         if ( !mf ) {
01361                                                 mf = get_free_spill_space(next->operand_get()->type_get());
01362                                                 next->allocated_spill_place_set(mf);
01363                                         }
01364                                         
01365                                         ptr<ge_operand_mem> spill_place = mf->get_ge_mem(NULL);
01366                                         copy_code = move_gen->generate_store_to_memory(interval->operand_get(),source_reg,spill_place);
01367                                         spill_place->origin_set(copy_code->back());
01368                                         
01369                                         mf2ge_pi__type::iterator mf_it = spill_space_last_use->find(mf);
01370                                         if ( mf_it!=spill_space_last_use->end() ) {
01371                                                 deplog << "U. " << copy_code->front()->uid_get() << " -> " <<  mf_it->second->uid_get() << "\n" << eolog;
01372                                                 copy_code->front()->dependencies_get()->insert(mf_it->second);
01373                                         }
01374                                         
01375                                         ptr<ge_pi> prev_use = find_last_use_of_register(source_reg->id_get());
01376                                         if ( prev_use ) {
01377                                                 deplog << "V. " << copy_code->front()->uid_get() << " -> " <<  prev_use->uid_get() << "\n" << eolog;
01378                                                 copy_code->front()->dependencies_get()->insert(prev_use);
01379                                         }
01380                 
01381                                         set_last_use_of_register(source_reg->id_get(),copy_code->back());
01382                                         (*spill_space_last_use)[mf] = copy_code->back();
01383                                 }
01384                                 
01385                                 if ( copy_code ) {
01386                                         //Insert the copy code to a basic block.
01387                                         ptr<basic_block> bb = interval->instructions_get()->back()->bb_get();
01388                                         bb->instructions_get()->insert(bb->instructions_get()->end(),copy_code->begin(),copy_code->end());
01389                                         
01390 #ifdef BACKEND_V2_DEBUG         
01391                                 ::std::ostringstream oss1;
01392                                 oss1 << "copy code between intervals (i1=" << interval->uid_get() << ", i2=" << next->uid_get() << ")";
01393                                 set_instruction_property(copy_code,ge_pi::PROPERTY_SPILLGEN_INFO,oss1.str());
01394 #endif
01395                                 }
01396                                 
01397                         } else {
01398                                 if ( interval->allocated_spill_place_get() ) {
01399                                         free_spill_spaces->insert(interval->allocated_spill_place_get());
01400                                 }
01401                         }       
01402                         
01403                         if ( interval->allocated_reg_get() && (*register_owners)[interval->allocated_reg_get()->id_get()]==interval ) {
01404                                 b_free_regs_need_recalculate = true;
01405                                 used_registers->erase(interval->allocated_reg_get()->id_get());
01406                                 register_owners->erase(interval->allocated_reg_get()->id_get());
01407                         }
01408                 } else {
01409                         ++it;
01410                 }
01411         }
01412         
01413         slog << "expire_old_intervals end\n" << eolog;
01414         
01415         return b_free_regs_need_recalculate;
01416         
01417 }
01418 
01419 /*!
01420         \brief Returns a pseudoinstruction that is the last user of a register.
01421         \param regid The register.
01422         \return The last user.
01423 */
01424 ptr<ge_pi> spillgen::find_last_use_of_register(ulint regid) {
01425         slog << "find_last_use_of_register start\n" << eolog;
01426         
01427         reg2ge_pi__type::iterator it = register_last_use->find(regid);
01428         
01429         slog << "find_last_use_of_register end\n" << eolog;
01430         return it==register_last_use->end() ? NULL : it->second;
01431 }
01432 
01433 /*!
01434         \brief Sets a pseudoinstruction as the last user of a register.
01435         \param regid The register.
01436         \param ge The last user.
01437 */
01438 void spillgen::set_last_use_of_register(ulint regid, ptr<ge_pi> ge) {
01439         slog << "set_last_use_of_register start\n" << eolog;
01440         
01441         ptr<tm_register> reg = tm_register::instance(regid);
01442         ptr<id_set__type> aliases = reg->aliases_get();
01443         
01444         for(id_set__type::iterator it = aliases->begin(); it!=aliases->end(); ++it) {
01445                 (*register_last_use)[*it] = ge;
01446         }
01447         
01448         slog << "set_last_use_of_register end\n" << eolog;
01449 }
01450 
01451 /*!
01452         \brief Inserts a vector of pseudoinstructions into a basic block.
01453         \param bb The basic block.
01454         \param code The vector of instructions.
01455         \param back True if the instructions should be at the end of the block, false for beginning.
01456 */
01457 void spillgen::insert_code_to_bb(ptr<basic_block> bb, ptr<ge_pi_vector__type> code, bool back) {
01458         for(ge_pi_vector__type::iterator it = code->begin(); it!=code->end(); ++it) {
01459                 (*it)->bb_set(bb);
01460         }
01461 
01462         if ( back ) {
01463                 bb->instructions_get()->insert(bb->instructions_get()->end(),code->begin(),code->end());
01464         } else {
01465                 bb->instructions_get()->insert(bb->instructions_get()->begin(),code->begin(),code->end());
01466         }
01467 }
01468 
01469 
01470 /*!
01471         \brief Adds a custom property value to a list of pseudoinstructions.
01472         
01473         \param instrs The list.
01474         \param property_id A id of the property.
01475         \param property_Value The value.
01476 */
01477 void spillgen::set_instruction_property(ptr<ge_pi_vector__type> instrs,ulint property_id,lstring property_value) {
01478         for(ge_pi_vector__type::iterator it = instrs->begin(); it!=instrs->end(); ++it) {       
01479                 ptr<ge_pi> ge = *it;
01480                 
01481                 if ( !ge->properties_get() ) {
01482                         ge->properties_set(id2lstring__type::create());
01483                 }
01484                 
01485                 (*ge->properties_get())[property_id] = property_value;
01486         }
01487 }       
01488 
01489 /*!
01490         \brief Returns data of the processed function with spill-code included.
01491 */
01492 ptr< ::lestes::backend_v2::structs::func_data > spillgen::get_result() {
01493         slog << "get_result start\n" << eolog;
01494 
01495         slog << "get_result end\n" << eolog;
01496         return data_get();
01497 }
01498 
01499 
01500 
01501 end_package(workers);
01502 end_package(backend_v2);
01503 end_package(lestes);
01504 

Generated on Mon Feb 12 18:23:15 2007 for lestes by doxygen 1.5.1-20070107