00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "c_breeze.h"
00039 #include "asm_gen_walker.h"
00040 #include "lir_flow_walker.h"
00041 #include "LIR.h"
00042 #include "hash_set_ex.h"
00043 #include "ref_clone_changer.h"
00044
00045 asm_gen_walker::asm_gen_walker ():Walker (Both, NodeOnly)
00046 {
00047 _unit = NULL;
00048 _pOutFile = NULL;
00049 }
00050
00051 asm_gen_walker::~asm_gen_walker ()
00052 {
00053 }
00054
00055 void
00056 asm_gen_walker::at_unit (unitNode * the_unit, Order ord)
00057 {
00058 if (ord == Preorder) {
00059
00060 _unit = the_unit;
00061
00062
00063
00064 string file = _unit->input_file();
00065 file[file.size()-1] = 's';
00066 _pOutFile = fopen (file.c_str (), "wt");
00067 if (!_pOutFile) {
00068 fprintf (stderr, "Can't open output file '%s' for writing.",
00069 file.c_str ());
00070 assert (false);
00071 }
00072
00073
00074 fprintf (_pOutFile, ".file \"%s\"\n\n", _unit->input_file ().c_str ());
00075
00076
00077 LirInst *begin = LIR::BeginUnit (_unit);
00078 emit (begin);
00079 delete begin;
00080
00081
00082 emit (_unit->instructions ());
00083
00084
00085 const def_list & defs = _unit->defs ();
00086 def_list::const_iterator it = defs.begin ();
00087 while (it != defs.end ())
00088 (*(it++))->walk (*this);
00089 }
00090 else {
00091
00092 LirInst *end = LIR::EndUnit (_unit);
00093 emit (end);
00094 delete end;
00095
00096
00097 fprintf (_pOutFile, "\n\n");
00098 fclose (_pOutFile);
00099 _pOutFile = NULL;
00100
00101
00102 _unit = NULL;
00103 }
00104 }
00105
00106 void
00107 asm_gen_walker::at_proc (procNode * the_proc, Order ord)
00108 {
00109
00110 if (ord != Preorder) {
00111 _proc = NULL;
00112 return;
00113 }
00114
00115
00116 _proc = the_proc;
00117
00118 #define CHECK_REG( reg ) \
00119 do { \
00120 if ( ! CBZ::ArchInfo.get_reg_by_index( (reg).num(), dummy ) ) \
00121 CBZFAIL(("Instruction '%s' uses virtual register.\n" \
00122 "Did you forget to specify a register allocation " \
00123 "phase or -noreg on the command line?", \
00124 inst->to_string().c_str())); \
00125 } while (0)
00126
00127
00128 instruction_list & insts = the_proc->instructions ();
00129 instruction_list_p it = insts.begin ();
00130 for (; it != insts.end (); ++it) {
00131 LirInst *inst = *it;
00132 Register dummy;
00133 if (inst->has_opnd1 ())
00134 CHECK_REG (inst->opnd1);
00135 if (inst->has_opnd2 ())
00136 CHECK_REG (inst->opnd2._reg);
00137 if (inst->has_base ())
00138 CHECK_REG (inst->memBase);
00139 if (inst->has_offset ())
00140 CHECK_REG (inst->memOffset._reg);
00141 if (inst->has_dest ())
00142 CHECK_REG (inst->dest);
00143 }
00144
00145 #undef CHECK_REG
00146
00147
00148 doCalleeSave ();
00149
00150
00151 doCallerSave ();
00152
00153
00154 computeStackFrameSize ();
00155
00156
00157 emit (insts);
00158
00159 }
00160
00161 void
00162 asm_gen_walker::computeStackFrameSize ()
00163 {
00164 assert (_proc);
00165
00166
00167
00168
00169
00170
00171
00172 unsigned int stackSize = _proc->get_locals_size ();
00173
00174
00175 unsigned int procArgSize = 0;
00176 instruction_list & insts = _proc->instructions ();
00177 instruction_list_p it = insts.begin ();
00178 for (; it != insts.end (); ++it) {
00179 LirInst & inst = **it;
00180 if (inst.instruction == mn_Call) {
00181
00182 if (procArgSize < inst.stack_arg_bytes ())
00183 procArgSize = inst.stack_arg_bytes ();
00184 }
00185 }
00186
00187
00188 stackSize += procArgSize;
00189 stackSize += CBZ::ArchInfo.get_stack_extra_bottom ();
00190 if (stackSize < CBZ::ArchInfo.get_stack_frame_min_size ())
00191 stackSize = CBZ::ArchInfo.get_stack_frame_min_size ();
00192
00193
00194 unsigned int align = CBZ::ArchInfo.get_stack_align ();
00195 stackSize = ((stackSize + align - 1) / align) * align;
00196
00197
00198 _proc->stack_frame_size (stackSize);
00199 }
00200
00201 void
00202 asm_gen_walker::doCalleeSave ()
00203 {
00204 assert (_proc);
00205 instruction_list & insts = _proc->instructions ();
00206
00207
00208 const arch_info::register_info_list & calleeSaveRegs =
00209 CBZ::ArchInfo.get_regs_callee_save ();
00210 if (calleeSaveRegs.size () == 0)
00211 return;
00212
00213 typedef hash_set_ex < unsigned int >regSet;
00214
00215
00216 regSet calleeSaveRegSet;
00217 arch_info::register_info_list::const_iterator csrit =
00218 calleeSaveRegs.begin ();
00219 while (csrit != calleeSaveRegs.end ())
00220 calleeSaveRegSet.insert ((*(csrit++))->_id);
00221
00222
00223
00224
00225 vector < instruction_list_p > returns;
00226 regSet changedRegSet;
00227 instruction_list_p it = insts.begin ();
00228 for (; it != insts.end (); ++it) {
00229 LirInst & inst = **it;
00230
00231
00232 if (inst.instruction == mn_Return)
00233 returns.push_back (it);
00234
00235
00236 if (inst.has_dest ())
00237 changedRegSet.insert (inst.dest.num ());
00238
00239
00240 arch_info::register_info_list killRegs;
00241 CBZ::ArchInfo.get_instruction_kill_regs (&inst, killRegs);
00242 arch_info::register_info_list_p kit = killRegs.begin ();
00243 for (; kit != killRegs.end (); ++kit)
00244 changedRegSet.insert ((*kit)->_id);
00245 }
00246
00247
00248 changedRegSet &= calleeSaveRegSet;
00249
00250
00251 if (changedRegSet.size () == 0)
00252 return;
00253
00254
00255 instruction_list_p firstRealInst = insts.begin ();
00256 while ((*firstRealInst)->instruction != mn_BeginProc
00257 && firstRealInst != insts.end ())
00258 firstRealInst++;
00259 assert (firstRealInst != insts.end ());
00260 LirInst *pBeginProc = *firstRealInst;
00261 firstRealInst++;
00262
00263
00264 regSet::iterator toSave = changedRegSet.begin ();
00265 for (; toSave != changedRegSet.end (); ++toSave) {
00266
00267 Register reg;
00268 typeNode * the_type;
00269 declNode * decl;
00270 createTempForRegSave (*toSave, reg, the_type, decl);
00271
00272
00273 LirInst *pStore = LIR::Store (the_type, reg, decl, Register::getRegFp (),
00274 DATA_CONTENTS_FRAMEP,
00275 decl->storage_location ()._stack_offset,
00276 NULL);
00277
00278
00279
00280 insts.insert (firstRealInst, pStore);
00281
00282
00283 vector < instruction_list_p >::iterator rtIt = returns.begin ();
00284 for (; rtIt != returns.end (); ++rtIt) {
00285
00286 LirInst *pLoad = LIR::Load (the_type, reg, decl, Register::getRegFp (),
00287 DATA_CONTENTS_FRAMEP,
00288 decl->storage_location ()._stack_offset,
00289 NULL);
00290
00291
00292 insts.insert (*rtIt, pLoad);
00293 assert ((**rtIt)->instruction == mn_Return);
00294 }
00295 }
00296
00297 }
00298
00299 void
00300 asm_gen_walker::doCallerSave ()
00301 {
00302 assert (_proc);
00303 instruction_list & insts = _proc->instructions ();
00304
00305
00306 reg_id_set caller_save;
00307 const arch_info::register_info_list & csave =
00308 CBZ::ArchInfo.get_regs_caller_save ();
00309 arch_info::register_info_list::const_iterator cs = csave.begin ();
00310 for (; cs != csave.end (); ++cs)
00311 caller_save |= (*cs)->_id;
00312
00313
00314 inst_to_reg_id_map liveRegs;
00315 lir_flow_walker::computeRegisterLiveness (insts, liveRegs);
00316
00317
00318 #if 0
00319 {
00320 cout << "DEBUG:" << endl;
00321 cout << "Liveness:" << endl;
00322 instruction_list_p it = insts.begin ();
00323 for (; it != insts.end (); ++it) {
00324 cout << " Live: ";
00325 reg_id_set_p live = liveRegs[*it].begin ();
00326 for (; live != found->second.end (); ++live) {
00327 arch_info::register_info * info =
00328 CBZ::ArchInfo.get_all_regs ()[*live];
00329 cout << info->_name << " ";
00330 }
00331 cout << endl;
00332 cout << "Inst: " << **it << endl;
00333 }
00334 cout << "END DEBUG" << endl;
00335 }
00336 #endif
00337
00338
00339
00340 instruction_list_p it = insts.begin ();
00341 Register regRetFixed = Register::getRegRetValFixed ();
00342 Register regRetFloat = Register::getRegRetValFloat ();
00343 for (; it != insts.end (); ++it) {
00344
00345 LirInst *inst = *it;
00346
00347
00348 if (inst->instruction != mn_CallPre)
00349 continue;
00350
00351
00352 reg_id_set live = liveRegs[inst];
00353 live &= caller_save;
00354 if (live.size () == 0)
00355 continue;
00356
00357
00358 instruction_list_p sequence = it;
00359 sequence++;
00360
00361
00362 LirInst *call = NULL;
00363 while (it != insts.end () && (*it)->instruction != mn_Call)
00364 it++;
00365 assert (it != insts.end ());
00366 call = *it;
00367 instruction_list_p postCall = it;
00368 postCall++;
00369 assert (postCall != insts.end ());
00370
00371
00372 typeNode * the_type = call->nodeExtra->type();
00373 Register *pRegRet = NULL;
00374 if ( the_type->is_float() )
00375 pRegRet = ®RetFloat;
00376 else if ( the_type->is_integer() || the_type->is_pointer() )
00377 pRegRet = ®RetFixed;
00378
00379
00380 reg_id_set_p toSave = live.begin ();
00381 for (; toSave != live.end (); ++toSave) {
00382
00383 assert (*toSave != pRegRet->num ());
00384
00385
00386 Register reg;
00387 typeNode * the_type;
00388 declNode * decl;
00389 createTempForRegSave (*toSave, reg, the_type, decl);
00390
00391
00392 LirInst *pStore = LIR::Store (the_type, reg, decl, Register::getRegFp (),
00393 DATA_CONTENTS_FRAMEP,
00394 decl->storage_location ()._stack_offset,
00395 NULL);
00396
00397
00398 insts.insert (sequence, pStore);
00399
00400
00401 LirInst *pLoad = LIR::Load (the_type, reg, decl, Register::getRegFp (),
00402 DATA_CONTENTS_FRAMEP,
00403 decl->storage_location ()._stack_offset,
00404 NULL);
00405
00406
00407 insts.insert (postCall, pLoad);
00408 }
00409 }
00410 }
00411
00412 void
00413 asm_gen_walker::createTempForRegSave (unsigned int id, Register & reg,
00414 typeNode *& the_type, declNode * &decl)
00415 {
00416
00417 CBZ::ArchInfo.get_reg_by_index (id, reg);
00418 assert (reg.type () == reg_gpr || reg.type () == reg_fpr);
00419 bool isgpr = (reg.type () == reg_gpr);
00420 the_type = (isgpr) ? CBZ::ArchInfo.get_reg_data_type_gpr ()
00421 : CBZ::ArchInfo.get_reg_data_type_fpr ();
00422
00423
00424 typeNode * declType = (typeNode *) ref_clone_changer::clone(the_type, false);
00425 declType->alloc_size(CBZ::ArchInfo.get_data_size(declType));
00426 declType->alloc_align(CBZ::ArchInfo.get_data_align(declType));
00427 decl = new declNode (reg.to_string ().c_str (), declNode::AUTO,
00428 declType, NULL, NULL);
00429 _proc->alloc_stack_local (decl);
00430 }
00431
00432 void
00433 asm_gen_walker::emit (const LirInst * inst)
00434 {
00435 assert (_pOutFile);
00436 if (!_pOutFile)
00437 return;
00438 if (!inst->should_emit ())
00439 return;
00440
00441
00442 vector < string > code;
00443 if (!CBZ::ArchInfo.get_code_for_instruction (inst, code))
00444 CBZFAIL (("Can't emit instruction '%s' because there is no code "
00445 "template for such an instruction in the architecture spec.",
00446 inst->to_string ().c_str ()));
00447
00448
00449 int i, sz = (int) code.size ();
00450 for (i = 0; i < sz; ++i)
00451 fprintf (_pOutFile, "%s\n", code[i].c_str ());
00452 }
00453
00454 void
00455 asm_gen_walker::emit (const instruction_list & insts)
00456 {
00457 assert (_pOutFile);
00458 if (!_pOutFile)
00459 return;
00460
00461
00462 instruction_list::const_iterator it = insts.begin ();
00463 for (; it != insts.end (); ++it) {
00464
00465 emit (*it);
00466 }
00467 }