pi_pi2ge_pi_base.cc

Go to the documentation of this file.
00001 /*!
00002         \file
00003         \author jaz
00004 */
00005 
00006 #include <lestes/backend_v2/debug/debug.hh>
00007 #include <lestes/backend_v2/intercode/pi.g.hh>
00008 #include <lestes/backend_v2/intercode/visitor_pi_pi2pi_operands.g.hh>
00009 #include <lestes/backend_v2/structs/pi_operands.g.hh>
00010 #include <lestes/md/instructions/pi_pi2ge_pi_template_base.g.hh>
00011 #include <lestes/md/instructions/instruction_group.g.hh>
00012 #include <lestes/md/instructions/tm_instr.g.hh>
00013 #include <lestes/md/types/tm_data_type.g.hh>
00014 #include <lestes/md/types/copy_constructor_call_generator.g.hh>
00015 #include <lestes/md/instructions/pi_pi2ge_pi_base.g.hh>
00016 
00017 package(lestes);
00018 package(md);
00019 package(instructions);
00020 
00021 using namespace ::lestes::backend_v2::debug;
00022 using namespace ::lestes::msg;
00023 using ::lestes::backend_v2::structs::pi_operands;
00024 using ::lestes::md::types::tm_dt_simple;
00025 using ::lestes::md::types::copy_constructor_call_generator;
00026 using namespace ::lestes::backend_v2::intercode;
00027 
00028 typedef list< ulint > ulint_list__type;
00029 typedef vector< ulint > ulint_vector__type;
00030 typedef set< ulint > ulint_set__type;
00031 typedef map< ulint, srp<tm_instr_op_base> > ulint2tm_instr_op_base__type;
00032 typedef map< ulint, ulint > ulint2ulint__type;
00033 typedef list< srp < instruction_group_base > > instruction_group_base_list__type;
00034 typedef vector< srp < tm_instr_op_base > > tm_instr_op_base_vector__type;
00035 typedef vector< srp < ge_operand > > ge_operand_vector__type;
00036 typedef vector< srp < ge_pi > > ge_pi_vector__type;
00037 typedef set< srp < ge_pi > > ge_pi_set__type;
00038 typedef vector< srp < ge_sp > > ge_sp_vector__type;
00039 typedef vector< srp < pi_sp > > pi_sp_vector__type;
00040 typedef map< ulint, srp<ge_operand> > ulint2ge_operand__type;
00041 typedef map< srp<pi_operand>, srp<ge_operand> > pi_op2ge_op__type;
00042 typedef map< srp<pi_sp>, srp<ge_sp> > pi_sp2ge_sp__type;
00043 
00044 
00045 declare_logger(log1);
00046 initialize_logger( log1, "pi_pi2ge_pi_base", md_logger );
00047 
00048 
00049 /*!
00050         \brief Converts a pi-pseudoinstruction to a corresponding list of ge-pseudoinstructions.
00051         
00052         The function takes an instance of pi_pi2ge_pi_template that contains list of instruction_group instances. It traverses the list
00053         and chooses one instruction from every instruction_group so that the choosed instruction are compatible ( operands that are passed
00054         among them are legal for every instruction ) and they together perform the requested operation.
00055         
00056         \param pi A pi-pseudoinstruction.
00057         \param pat A pi_pi2ge_pi template that describes possible conversions.
00058 */
00059 ptr<ge_pi_vector__type> pi_pi2ge_pi_base::convert(ptr<pi_pi> pi, ptr<pi_pi2ge_pi_template_base> pat) {
00060         log1 << "convert - start (pi=" << pi->reflection_get()->back()->name_get() << ")\n" << eolog;
00061         
00062         lassert(pi);
00063         lassert(pat);
00064         
00065         ptr<ulint_vector__type> selected_instrs = ulint_vector__type::create();
00066         ptr<ulint2tm_instr_op_base__type> selected_operands = ulint2tm_instr_op_base__type::create();
00067         ptr<ulint2ulint__type> selected_op_types = ulint2ulint__type::create();
00068         
00069         if ( !find_consistent_instructions(pi,pat,selected_instrs,selected_operands,selected_op_types,0) ) {
00070                 log1 << "convert - end 1 (bad)\n" << eolog;
00071                 return NULL;
00072         }
00073         
00074         log1 << "convert - end\n" << eolog;
00075         
00076         return generate_ge_code(pi,pat,selected_instrs,selected_op_types);
00077 }
00078 
00079 /*!
00080         \brief Setups dependencies among generated ge-pseudoinstructions.
00081         
00082         \param ge A ge-pseudoinstruction that needs dependenices to be set.
00083 */
00084 void pi_pi2ge_pi_base::setup_dependencies(ptr<ge_pi> ge) {
00085         log1 << "setup_dependencies - start\n" << eolog;
00086         
00087         ptr<pi_pi> pi = ge->pi_source_get();    
00088         ptr<ge_pi_set__type> dependencies = ge->dependencies_get();
00089         
00090         //Add the ge-pi that corresponds to the original pi-pseudoinstruction's psp to the dependency list.
00091         if ( pi->psp_get() ) {
00092                 //Set dependence on the last ge-pi that corresponds to the psp
00093                 ptr<ge_pi> ge_psp = (*pi_sp2ge_sp)[pi->psp_get().dncast<pi_sp>()];
00094                 lassert(ge_psp);
00095                 dependencies->insert(ge_psp);
00096         }
00097         
00098         //Add the ge-pi that corresponds to the original pi-pseudoinstruction's nsp to the dependency list.
00099         if ( pi->nsp_get() && pi->nsp_get()->psp_get()!=pi ) {
00100                 //Set dependence on the first ge-pi that corresponds to the nsp
00101                 ptr<ge_pi> ge_nsp = (*pi_sp2ge_sp)[pi->nsp_get().dncast<pi_sp>()];
00102                 lassert(ge_nsp);
00103                 ge_nsp->dependencies_get()->insert(ge);
00104         }
00105         
00106         
00107         //Add origins of input ge-operands to the dependency list.
00108         ptr<ge_operand_vector__type> in_ops = ge->operands_input_get();
00109         for(ge_operand_vector__type::size_type i=0; i<in_ops->size(); ++i) {
00110                 ptr<ge_operand> op = (*in_ops)[i];
00111                 
00112                 /*
00113                         Immediate has ho origin. 
00114                 */
00115                 if ( op->kind_get()!=ge_operand::IMMEDIATE ) {
00116                         ptr<ge_pi> origin = op->origin_get();
00117                         
00118                         if ( !origin ) {
00119                                 /*
00120                                         The operand is not output operand of any ge-instruction.
00121                                         It can happen if the operand is memmory operand referencing local variable or
00122                                         pi_mem_ptr_deref. 
00123                                 */
00124                                 ptr<pi_operand> pi_source = op->pi_source_get();
00125                                 
00126                                 if ( pi_source->kind_get()==pi_operand::MEM_PTR_DEREF ) {
00127                                         /*
00128                                                 Ptr_mem_deref is wrapper of a register. Its origin is the 
00129                                                 origin of the wrapped register. 
00130                                         */
00131                                         ptr<ge_operand> addr = pi_source.dncast<pi_mem>()->factory_get().dncast<pi_mf_ptr_deref>()->ge_addr_get();
00132                                         origin = addr->origin_get();
00133                                 } else {
00134                                         /*
00135                                                 Pi-source of memmory operand referencing local variable has pi-origin set to preceding pi-sequencepoint.
00136                                                 So we take ge-pseudoinstruction that corresponds to the pi-sp and set it as
00137                                                 origin of the ge-operand.
00138                                         */
00139                                         origin = (*pi_sp2ge_sp)[pi_source->origin_get().dncast<pi_sp>()];
00140                                 }
00141                                 op->origin_set(origin);
00142                         }
00143                         
00144                         lassert(origin);
00145                         dependencies->insert(origin);
00146                 }
00147         }       
00148         
00149         
00150         log1 << "setup_dependencies - end\n" << eolog;
00151         
00152 }
00153 
00154 /*!
00155         \brief Gets list of selected target machine instruction ids for each instruction_group and generates output ge-code.
00156         
00157         \param pi A pi-pseudoinstruction.
00158         \param pat A list of instruction_group instances.
00159         \param choosed_instructions Selected instructions.
00160         \param  choosed_op_types Types of operands used within output code.
00161         \return Vector of ge-pi instructions.
00162 */
00163 ptr<ge_pi_vector__type> pi_pi2ge_pi_base::generate_ge_code(ptr<pi_pi> pi, ptr<pi_pi2ge_pi_template_base> pat, ptr<ulint_vector__type> choosed_instrs,  ptr<ulint2ulint__type> choosed_op_types) {
00164         log1 << "generate_ge_code - start\n" << eolog;
00165         
00166         ptr<ge_pi_vector__type> output = ge_pi_vector__type::create();
00167         ptr<ulint2ge_operand__type> tm_op2ge_op = ulint2ge_operand__type::create();     
00168         ptr<pi_operands> pi_ops = pi->accept_visitor_pi_pi2pi_operands_gen_base(pi_operands_getter);
00169         
00170         ptr<ge_pi> prev;
00171         
00172         /*
00173                 Go throught the pi2ge templates's instruction groups and generate output code according to the selected versions.
00174         */
00175         for(::lestes::std::vector< srp< instruction_group_base > >::size_type i=0; i<pat->instruction_groups_get()->size(); ++i) {
00176                 //The instruction group
00177                 ptr<instruction_group_base> instr_group = (*pat->instruction_groups_get())[i];
00178                 //The selected version.
00179                 ptr<tm_instr_base> instr_version = tm_instr::instance((*choosed_instrs)[i]);
00180                                 
00181                 //Output ge-code
00182                 ptr<ge_pi> ge = ge_pi::create(instr_version,pi);
00183                 
00184                 ptr<ge_operand_vector__type> input_ops = ge->operands_input_get();
00185                 ptr<ge_operand_vector__type> output_ops = ge->operands_output_get();
00186                 ptr<ge_pi_set__type> dependencies = ge->dependencies_get();
00187                 
00188                 if ( prev ) {
00189                         /*
00190                                 Set dependence on a preceeding output ge-pseudoinstruction of the teplate in order to force the output
00191                                 code to be ordered in the same way as instruction groups in the input template. 
00192                         */
00193                         
00194                         dependencies->insert(prev);
00195                 }
00196                 
00197                 //Input operands.
00198                 for(::lestes::std::vector< ulint >::size_type j=0; j<instr_group->input_operand_pids_get()->size(); ++j) {      
00199                         //Pid of an output ge-operand that is passed to this input opperand from a preceeding ge-pseudoinstruction.
00200                         ulint operand_pid = (*instr_group->input_operand_pids_get())[j];
00201                         //Id of an input operand of the selected target instruction.
00202                         ulint operand_ref = (*instr_group->input_operand_refs_get())[j];
00203 
00204                         ptr<tm_instr_op_base> tm_op = (*instr_version->operands_input_get())[j];
00205                         lassert(tm_op->id_get()==operand_ref);
00206                         
00207                         ptr<ge_operand> ge_op;
00208                         
00209                         if ( operand_pid <= PIN_4 ) {
00210                                 //The operand coresponds to the input pi-operand of the input pi-pseudoinstruction.
00211                                 ulint i_op_pos = operand_pid - PIN_1;
00212                                 ptr<pi_operand> pi_op = (*pi_ops->operands_input_get())[i_op_pos];
00213 
00214                                 //Convert pi-operand to ge-operand
00215                                 ge_op = pi_op2ge_op_convertor->convert(pi_op);
00216                                 
00217                                 if ( tm_op->destroyed_by_get()->size()!=0 && (*pi_op2count)[pi_op] > 1 ) {
00218                                         /*
00219                                                 The input operand is destroyes(overwritten) by an output operand. When the instruction is performed, the operand's
00220                                                 value is overwritten by output value. But the original value 
00221                                                 will be required somewhere later. So we must preserve the original value by copying to
00222                                                 the another destroyable operand. Then the copy of the operand will be used instead the preserved one.
00223                                         */
00224                                         ptr<ge_pi_vector__type> copy_code = ge_pi_vector__type::create();
00225 
00226                                         ge_op = copy_constructor_call_generator::instance()->generate_copy(ge_op,copy_code);
00227                                 
00228                                         //Append copy-code to the output code.
00229                                         for(ulint k=0; k<copy_code->size(); ++k) {
00230                                                 ptr<ge_pi> cp = (*copy_code)[k];
00231                                                 cp->pi_source_set(pi);
00232                                                 output->push_back(cp);
00233                                         
00234                                                 /*
00235                                                         Note: The ge-pseudoinstruction has to be executed after the copy instructions.
00236                                                         It is accomplished by adding origin of the copy of the operand to list of dependecies
00237                                                         of the ge-pseudoinstruction that uses it. This is done during the setup_dependencies phase.
00238                                                 */
00239                                         }                               
00240                                 }
00241                         } else {
00242                                 //The operand's source is an output operand of preceeding ge-pseudoinstruction. 
00243                                 //Find the output operand.
00244                                 ulint2ge_operand__type::iterator it_ge = tm_op2ge_op->find(operand_pid);
00245                                 lassert(it_ge!=tm_op2ge_op->end());
00246                                 ge_op = it_ge->second;
00247                         }               
00248                         
00249                         input_ops->push_back(ge_op);
00250                 }       
00251                 
00252                 //Output operands.
00253                 for(ulint j=0; j<instr_group->output_operand_pids_get()->size(); ++j) { 
00254                         //Pid of an output ge-operand.
00255                         ulint operand_pid = (*instr_group->output_operand_pids_get())[j];
00256                         //Id of an output operand of the selected target instruction.
00257                         ulint operand_ref = (*instr_group->output_operand_refs_get())[j];
00258 
00259                         ptr<ge_operand> ge_op;
00260                                                 
00261                         if ( operand_pid <= POUT_4 ) {
00262                                 //The operand coresponds to the output pi-operand of the input pi-pseudoinstruction.
00263                                 ulint i_op_pos = operand_pid - POUT_1;
00264                                 ptr<pi_operand> pi_op = (*pi_ops->operands_output_get())[i_op_pos];
00265 
00266                                 //Convert pi-operand to ge-operand
00267                                 ge_op = pi_op2ge_op_convertor->convert(pi_op);
00268                                         
00269                         } else {
00270                                 //Regular output operand need to be generated.
00271                                 ptr<tm_instr_op_base> tm_op = (*instr_version->operands_output_get())[j];
00272                                 lassert(tm_op->id_get()==operand_ref);
00273                                 
00274                                 //Data type of the operand.
00275                                 ulint type;
00276                                 
00277                                 if ( tm_op->allowed_types_get()->size()==1 ) {
00278                                         //The operand has only single type allowed.
00279                                         type = *tm_op->allowed_types_get()->begin();
00280                                 } else {
00281                                         //The operand has multiple types allowed.
00282                                         lassert(instr_group->input_operand_pids_get()->size()>0);
00283                                 
00284                                         /*
00285                                                 Which one of the allowed types should we take?
00286                                                 
00287                                                 This is the tricky part. Possibilities:
00288                                                         1. Only single allowed type has to be allowed for an operand.
00289                                                         2. New attribute that tells which one of the input operands has the same type.
00290                                                         3. The type is the same one as the allowed type of the first input operand.
00291                                                         4. Something else.      
00292                                                 
00293                                                 The selected solution is 4:
00294                                                         - the output type is the same as the type of the first input operand.
00295                                                         
00296                                                 The writer of the machine description file should be aware of this mechanism, so the instruction
00297                                                 that has multiple allowed output types and doesn'd fulfil the requirement should be rewritten into
00298                                                 multiple instructions with single output type. 
00299                                         */
00300                                         ulint iop_pid = (*instr_group->input_operand_pids_get())[0];
00301                                         ulint2ulint__type::iterator it_t = choosed_op_types->find(iop_pid);
00302                                         lassert(it_t!=choosed_op_types->end());
00303                                         
00304                                         type = it_t->second;
00305                                         
00306                                         //Check that the type is among allowed ones.
00307                                         lassert(tm_op->allowed_types_get()->find(type)!=tm_op->allowed_types_get()->end());
00308                                 }
00309                                 
00310                                 //Convert operand of the tm_inst template to ge-operand.
00311                                 ge_op = tm_op->convert_to_ge(tm_dt_simple::instance((::lestes::md::types::dt_id_type)type));
00312                                  
00313                                 tm_op2ge_op->insert(::std::pair<ulint, srp<ge_operand> >(operand_pid,ge_op));
00314                         }
00315                         
00316                         //Set origin of the operand.
00317                         ge_op->origin_set(ge);
00318                         
00319                         //add operand to list of output operands
00320                         output_ops->push_back(ge_op);
00321                 }
00322                 
00323                 if ( instr_version->is_jump() ) {
00324                         //Setup jump targets
00325                         ptr<ge_sp_vector__type> jmp_targets = ge_sp_vector__type::create();
00326                 
00327                         ptr<pi_sp_vector__type> pi_targets = pi_ops->jmp_targets_get();
00328                         for(ulint j=0; j<pi_targets->size(); ++j) {
00329                                 ptr<ge_sp> jmp_target = (*pi_sp2ge_sp)[(*pi_targets)[j]];
00330                                 jmp_target->is_jmp_target_set(true);
00331                                 jmp_targets->push_back(jmp_target);
00332                         }       
00333                 
00334                         ge->jmp_targets_set(jmp_targets);
00335                 }
00336                 ge->validate(); 
00337                 output->push_back(ge);
00338         }
00339         
00340         log1 << "generate_ge_code - end\n" << eolog;
00341         
00342         return output;
00343 }
00344 
00345 
00346 /*!
00347         \brief Recursively traverses list of instruction_groups and chooses one instruction from each instruction_group that is consistent with the ones previously choosed.
00348         
00349         \param pi A converted pseudoinstruction.
00350         \param pat An examinated list of instruction_groups.
00351         \param selected_instrs A list of selected instructions from preceeding steps.
00352         \param selected_operands A list of operands of selected instructions from preceding steps.
00353         \param selected_op_types A list of datatypes of selected_operands.
00354         \param curr_instrs_pat_idx An index of the currentky examinated instruction_group.
00355         \return False if no one instruction from the examinated instruction_group is consistent with the ones choosed in previous steps.
00356 */
00357 bool pi_pi2ge_pi_base::find_consistent_instructions(ptr<pi_pi> pi, ptr<pi_pi2ge_pi_template_base> pat, ptr<ulint_vector__type> selected_instrs, ptr<ulint2tm_instr_op_base__type> selected_operands, ptr<ulint2ulint__type> selected_op_types, ulint curr_instrs_pat_idx) {
00358         log1 << "find_consisten_instructions - start\n" << eolog;
00359         
00360         if ( curr_instrs_pat_idx==pat->instruction_groups_get()->size() ) {
00361                 //All the instruction groups has been visited. Terminate recursion.
00362                 log1 << "find_consisten_instructions - end 1\n" << eolog;
00363                 return true;
00364         }
00365         
00366         //Testedd instruction group.
00367         ptr<instruction_group_base> instr_group = (*pat->instruction_groups_get())[curr_instrs_pat_idx];
00368         
00369         //Go through possible instructions and find the suitable one.
00370         for(ulint i=0; i<instr_group->instructions_get()->size(); ++i) {
00371                 ulint instr_version_id = (*instr_group->instructions_get())[i];
00372                 ptr<tm_instr_base> instr_version = tm_instr::instance(instr_version_id);
00373                 
00374                 if ( !is_instruction_consistent(instr_group,instr_version,pi,selected_operands,selected_op_types) ) {
00375                         //The instruction is not suitable.
00376                         continue;
00377                 }
00378                 
00379                 //Add operands of the suitable instruction to the selected_operands list.
00380                 add_selected_operands(instr_group,instr_version,pi,selected_operands,selected_op_types);
00381                 selected_instrs->push_back(instr_version_id);
00382                 
00383                 //Check whether exists instruction for every consequent instruction_groups that are suitable with the instructio version.
00384                 if ( find_consistent_instructions(pi,pat,selected_instrs,selected_operands,selected_op_types,curr_instrs_pat_idx+1) ) {
00385                         //Yes, they exists.
00386                         log1 << "find_consisten_instructions - end 2 (good)\n" << eolog;
00387                         return true;
00388                 }
00389                 
00390                 //No, for some of the consequent instructions group don't exist suitable instruction. Rollback and try another version.
00391                 remove_selected_operands(instr_group,selected_operands,selected_op_types);
00392                 selected_instrs->pop_back();
00393         }
00394         
00395         log1 << "find_consisten_instructions - end (bad)\n" << eolog;
00396         return false;
00397 }
00398 
00399 /*!
00400         \brief Checks whether a tm_instr is compatible with operands that are passed to it from preceding instructions.
00401         
00402         \param instr_group A group of instructions.
00403         \param instr_version A instruction to be tested.
00404         \param pi A source pi-pseudoinstruction.
00405         \param selected_operands A list of operands of preceding instructions.
00406         \param selected_types A list of datatypes of the selected_operands.
00407         \return True if the instruction is consistent. False otherwise.
00408 */
00409 bool pi_pi2ge_pi_base::is_instruction_consistent(ptr<instruction_group_base> instr_group, ptr<tm_instr_base> instr_version, ptr<pi_pi> pi, ptr<ulint2tm_instr_op_base__type> selected_operands,ptr<ulint2ulint__type> selected_types) {
00410         log1 << "is_instruction_consistent - start (tm_instr=" << instr_version->id_get() << ")\n" << eolog;
00411         
00412         /*
00413                 pi_pi2ge_pi_base::is_instruction_consistent is target-machine independent code. The following line is the way to
00414                 run any target dependent code required.
00415         */
00416         if ( !targetmachine__is_instruction_consistent(instr_version,pi) ) {
00417                 log1 << "is_instruction_consistent - end 1 (bad)\n" << eolog;
00418                 return false;
00419         }
00420         
00421         ptr<pi_operands> operands = pi->accept_visitor_pi_pi2pi_operands_gen_base(pi_operands_getter);
00422         /*
00423                 Go through input operands and check that are compatible with selected output operands of preceeding instructions.
00424         */
00425         for(ulint i=0; i<instr_group->input_operand_pids_get()->size(); ++i) {  
00426                 ulint operand_pid = (*instr_group->input_operand_pids_get())[i];
00427                 ulint operand_ref = (*instr_group->input_operand_refs_get())[i];
00428                 
00429                 lassert(operand_pid<=PIN_4 || operand_pid>POUT_4 );
00430                 
00431                 ptr<tm_instr_op_base> op = find_op_by_id(instr_version->operands_input_get(),operand_ref);
00432                 
00433                 if ( operand_pid <= PIN_4 ) {
00434                         //The operand coresponds to the input pi-operand of the input pi-pseudoinstruction.
00435                         ulint i_op_pos = operand_pid - PIN_1;
00436                         
00437                         lassert(operands->operands_input_types_get()->size()>i_op_pos);
00438                         if ( !is_operand_compatible1(op,(*operands->operands_input_get())[i_op_pos],(*operands->operands_input_types_get())[i_op_pos]->id_get()) ) {
00439                                 log1 << "is_instruction_consistent - end 2 (bad)\n" << eolog;
00440                                 return false;
00441                         }
00442                          
00443                 } else {
00444                         //Check compatibility with selected output operands of preceeding instructions.
00445                         ulint2tm_instr_op_base__type::iterator it_op = selected_operands->find(operand_pid);
00446                         ulint2ulint__type::iterator it_t = selected_types->find(operand_pid);
00447                         
00448                         lassert(it_op!=selected_operands->end());
00449                         lassert(it_t!=selected_types->end());
00450                         
00451                         if ( !is_operand_compatible2(op,it_op->second,it_t->second) ) {
00452                                 log1 << "is_instruction_consistent - end 3 (bad)\n" << eolog;
00453                                 return false;
00454                         }
00455                 }
00456         }
00457         
00458         /*
00459                 Go through output operands and check that are compatible with output operands of the pi-pseudoinstruction.
00460         */
00461         for(ulint i=0; i<instr_group->output_operand_pids_get()->size(); ++i) { 
00462                 ulint operand_ref = (*instr_group->output_operand_refs_get())[i];
00463                 ulint operand_pid = (*instr_group->output_operand_pids_get())[i];
00464                 
00465                 lassert(operand_pid > PIN_4);
00466                 
00467                 if ( operand_pid>=POUT_1 && operand_pid <= POUT_4 ) {
00468                         ptr<tm_instr_op_base> op = find_op_by_id(instr_version->operands_output_get(),operand_ref);
00469                         ulint i_op_pos = operand_pid - POUT_1;
00470                         
00471                         lassert(operands->operands_output_types_get()->size()>i_op_pos);
00472                         if ( !is_operand_compatible1(op,(*operands->operands_output_get())[i_op_pos],(*operands->operands_output_types_get())[i_op_pos]->id_get()) ) {
00473                                 log1 << "is_instruction_consistent - end 4 (bad)\n" << eolog;
00474                                 return false;
00475                         }
00476                          
00477                 } 
00478         }
00479         
00480         log1 << "is_instruction_consistent - end\n" << eolog;
00481         return true;
00482 }
00483 
00484 /*!
00485         \brief Checks whether a tm_instr_op is compatible with a pi_operand (i.e. the tm_instr_op can be converted to the pi_operand).
00486         
00487         \param instr_op A tm_instr_op instance.
00488         \param pi_op A pi_operand instance.
00489         \param pi_type A datataype of the pi_operand.
00490         \return True if operands are compatible. False otherwise.
00491 */
00492 bool pi_pi2ge_pi_base::is_operand_compatible1(ptr<tm_instr_op_base> instr_op, ptr<pi_operand> pi_op, ulint pi_type) {
00493         log1 << "is_operand_compatible1 - start (instr_op=" << instr_op->id_get() << ")\n" << eolog;
00494         
00495         if ( instr_op->allowed_types_get()->find(pi_type)==instr_op->allowed_types_get()->end() ) {
00496                 log1 << "is_operand_compatible1 - end1 (bad)\n" << eolog;
00497                 return false;
00498         }
00499         
00500         ulint kind1 = instr_op->kind_get();
00501         ulint kind2 = pi_op->kind_get();
00502         
00503         if ( ( kind1==tm_instr_op_base::REGISTER && ( kind2!=pi_operand::PREG && kind2!=pi_operand::MEM_PREG)) ||
00504                  ( kind1==tm_instr_op_base::IMMEDIATE && kind2!=pi_operand::LIT ) ||
00505                  ( kind1==tm_instr_op_base::MEMORY && (kind2==pi_operand::MEM_PREG || kind2==pi_operand::PREG || kind2==pi_operand::LIT) ) ) {
00506                  log1 << "is_operand_compatible1 - end2 (bad)\n" << eolog;
00507                  return false;
00508         }
00509          
00510         log1 << "is_operand_compatible1 - end\n" << eolog;
00511         return true;
00512 }
00513 
00514 /*!
00515         \brief Traverses a list and tells whether a value is contained.
00516         
00517         \param list A list.
00518         \param value A value.
00519         \return True if the value is in the list. False otherwise.
00520 */
00521 bool pi_pi2ge_pi_base::is_in(ptr<vector<ulint> > list, ulint value) {
00522         for(uint i=0; i<list->size(); ++i) {
00523                 if ( (*list)[i]==value ) {
00524                         return true;
00525                 }
00526         }
00527         return false;
00528 }
00529 
00530 /*!
00531         Checks whether two operands have the same kind, nonempty intersection of allowed datatypes and nonempty set of allowed registers in case that the kind of the operands is register.
00532         
00533         \param op1 An operand.
00534         \param op2 An operand.
00535         \type type A type of the op2.
00536         \return True it the operands are compatible. False otherwise.
00537 */
00538 bool pi_pi2ge_pi_base::is_operand_compatible2(ptr<tm_instr_op_base> op1, ptr<tm_instr_op_base> op2, ulint type) {
00539         log1 << "is_operand_compatible2 - start (instr_op=" << op1->id_get() << ")\n" << eolog;
00540         
00541         if ( op1->allowed_types_get()->find(type)==op1->allowed_types_get()->end() ) {
00542                 log1 << "is_operand_compatible2 - end 1 (bad)\n" << eolog;
00543                 return false;
00544         }
00545         
00546         if ( op1->kind_get()!=op2->kind_get() ) {
00547                 log1 << "is_operand_compatible2 - end 2 (bad)\n" << eolog;
00548                 return false;
00549         }
00550         
00551         if ( op1->kind_get()==tm_instr_op_base::REGISTER ) {
00552                 ptr<ulint_set__type> allowed_regs1 = op1.dncast<tm_instr_op_reg_base>()->allowed_registers_get();
00553                 ptr<ulint_set__type> allowed_regs2 = op2.dncast<tm_instr_op_reg_base>()->allowed_registers_get();
00554                 ptr<ulint_set__type> allowed_intersec = ulint_set__type::create();
00555                 
00556                 ::std::set_intersection(
00557                         allowed_regs1->begin(),
00558                         allowed_regs1->end(),
00559                         allowed_regs2->begin(),
00560                         allowed_regs2->end(),
00561                         ::std::inserter(*allowed_intersec, allowed_intersec->begin()));
00562                         
00563                 
00564                 if ( allowed_intersec->size()!=0 ) {
00565                         log1 << "is_operand_compatible2 - end 3 (good)\n" << eolog;
00566                         return true;
00567                 }
00568         }
00569         
00570         log1 << "is_operand_compatible2 - end (bad)\n" << eolog;
00571         return false;
00572 }
00573 
00574 /*!
00575         \brief Adds instruction's operands to a list of selected operands.
00576         
00577         \param instr_group A group of instructions.
00578         \param instr_version A parent instruction of the operands.
00579         \param pi A source pi-pseudoinstruction.
00580         \param selected_operands A list of operands of preceding instructions.
00581         \param selected_types A list of datatypes of the selected_operands.
00582 */
00583 void pi_pi2ge_pi_base::add_selected_operands(ptr<instruction_group_base> instr_group, ptr<tm_instr_base> instr_version, ptr<pi_pi> pi, ptr<ulint2tm_instr_op_base__type> selected_operands,ptr<ulint2ulint__type> selected_types) {
00584         ptr<pi_operands> operands = pi->accept_visitor_pi_pi2pi_operands_gen_base(pi_operands_getter);
00585         
00586         // Add output operands of the selected instruction version to the selected_operands list.  The types of the selected operands add to the selected_types list. 
00587         for(ulint i=0; i<instr_group->output_operand_pids_get()->size(); ++i) {
00588                 ulint operand_pid = (*instr_group->output_operand_pids_get())[i];
00589                 ulint operand_ref = (*instr_group->output_operand_refs_get())[i];
00590                 
00591                 lassert(operand_pid > PIN_4);
00592                 
00593                 ptr<tm_instr_op_base> op = find_op_by_id(instr_version->operands_output_get(),operand_ref);
00594                 selected_operands->insert(::std::pair<ulint, srp<tm_instr_op_base> >(operand_pid, op));         
00595                 
00596                 ulint type;
00597                 
00598                 if ( operand_pid>=POUT_1 && operand_pid <= POUT_4 ) {
00599                         //The type of the output operand that corresponds to the output operand of pi-pseudoinstruction is type od pi-operand.
00600                         ulint i_op_pos = operand_pid - POUT_1;
00601                         ptr<pi_operand> pi_op = (*operands->operands_output_get())[i_op_pos];
00602                         type = pi_op->type_get()->id_get();
00603                 } else {                        
00604                         if ( op->allowed_types_get()->size()==1 ) {
00605                                 //Operand has the only one type allowed.
00606                                 type = *op->allowed_types_get()->begin();
00607                         } else {
00608                                 //Operand has multiple types allowed. Take type of the first input operand.
00609                                 lassert(instr_group->input_operand_pids_get()->size()>0);
00610                                 ulint iop_pid = (*instr_group->input_operand_pids_get())[0];
00611                                 
00612                                 ulint2ulint__type::iterator it_t = selected_types->find(iop_pid);
00613                                 
00614                                 lassert(it_t!=selected_types->end());
00615                                 
00616                                 type = it_t->second;
00617                         }
00618                 }
00619                 
00620                 selected_types->insert(::std::pair<ulint, ulint>(operand_pid, type));           
00621         }
00622 }
00623 
00624 /*!
00625         \brief Removes instruction's operands to a list of selected operands.
00626         
00627         \param instr_group A group of instructions.
00628         \param selected_operands A list of operands of preceding instructions.
00629         \param selected_types A list of datatypes of the selected_operands.
00630 */
00631 void pi_pi2ge_pi_base::remove_selected_operands(ptr<instruction_group_base> instr_group, ptr<ulint2tm_instr_op_base__type> selected_operands, ptr<ulint2ulint__type> selected_types) {
00632         
00633         for(ulint i=0; i<instr_group->output_operand_pids_get()->size(); ++i) {
00634                 ulint operand_pid = (*instr_group->output_operand_pids_get())[i];
00635                 selected_operands->erase(operand_pid);          
00636                 selected_types->erase(operand_pid);             
00637         }
00638 }
00639 
00640 /*!
00641         \brief Traverses a list of operands and returns an operand with given id.
00642         
00643         \param list A list of operands.
00644         \param id An id of operand.
00645         \return A operand.
00646 */
00647 ptr<tm_instr_op_base> pi_pi2ge_pi_base::find_op_by_id(ptr<tm_instr_op_base_vector__type> list, ulint id) {
00648         for(uint i=0; i<list->size(); ++i) {
00649                 ptr<tm_instr_op_base> op = (*list)[i];
00650                 
00651                 if ( op->id_get()==id ) {
00652                         return op;
00653                 }
00654         }
00655         
00656         return NULL;;
00657 }
00658 
00659 
00660 end_package(instructions);
00661 end_package(md);
00662 end_package(lestes);
00663 

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