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
00039 #include "inliner.h"
00040
00041
00042 class identify_inlinees:public Walker
00043 {
00044 public:
00045 identify_inlinees(map<declNode *, procNode *> & m):
00046 Walker(Preorder, Subtree),
00047 _procmap(m) {};
00048 void at_threeAddr(threeAddrNode * ta, Order ord);
00049 inline set<threeAddrNode*> & callinline(){ return _callinline;}
00050 inline set<procNode *> & procs(){ return _procs;}
00051 inline set<procNode *> & inlined(){ return _inlined;}
00052
00053 private:
00054 set<threeAddrNode *> _callinline;
00055 map<declNode *, procNode *> & _procmap;
00056 set<procNode*> _procs;
00057 set<procNode*> _inlined;
00058 };
00059
00060
00076 void
00077 fi::run()
00078 {
00079 Linker l;
00080 unit_list_p up;
00081
00082
00083 for (up = CBZ::Program.begin(); up != CBZ::Program.end(); up++)
00084 cfg_changer::generate_cfg(*up);
00085
00086
00087
00088
00089 procNode * mainfunc = findmain();
00090
00091 l.link();
00092
00093
00094
00095 callGraph cg(mainfunc, l);
00096
00097
00102 identify_inlinees i_i(l.procedure_declarations());
00103 function_inline f(i_i.callinline(), l.procedure_declarations(),
00104 i_i.procs(), i_i.inlined());
00105
00106
00107 if(mainfunc)
00108 f.insert_proc(mainfunc);
00109 else
00110 perror("Whoops! Null root to callGraph.\n");
00111
00112
00113 for (up = CBZ::Program.begin(); up != CBZ::Program.end(); ++up)
00114 (*up)->walk(i_i);
00115
00116
00117 f.process(cg);
00118
00119
00120 for (up = CBZ::Program.begin(); up != CBZ::Program.end(); ++up)
00121 Dismantle::dismantle(*up);
00122
00123 }
00124
00125
00133 void
00134 function_inline::inline_functions(procNode * root)
00135 {
00136 Linker l;
00137 unit_list_p up;
00138
00139 if(root == NULL)
00140 {
00141 root = findmain();
00142 }
00143
00144 l.link();
00145 callGraph cg(root, l);
00146
00147 if(!root)
00148 perror("oh no! null to callgraph");
00149
00154 identify_inlinees i_i(l.procedure_declarations());
00155 function_inline f(i_i.callinline(), l.procedure_declarations(),
00156 i_i.procs(), i_i.inlined());
00157
00158 f.insert_proc(root);
00159
00160 for (up = CBZ::Program.begin(); up != CBZ::Program.end(); ++up)
00161 (*up)->walk(i_i);
00162
00163 f.process(cg);
00164
00165 for (up = CBZ::Program.begin(); up != CBZ::Program.end(); ++up)
00166 Dismantle::dismantle(*up);
00167
00168 }
00169
00170
00171
00172
00173 procNode * findmain()
00174 {
00175 unit_list_p up;
00176 procNode * mainfunc=NULL;
00177 for (up = CBZ::Program.begin(); up != CBZ::Program.end(); ++up)
00178 {
00179 unitNode * unit = *up;
00180
00181 for (def_list_p q = unit->defs().begin(); q != unit->defs().end(); ++q)
00182 {
00183 defNode * def = *q;
00184
00185 if (def->typ() == Proc)
00186 {
00187 procNode * pr = (procNode *) def;
00188 if (pr->decl()->name() == "main")
00189 {
00190 mainfunc=pr;
00191 }
00192 }
00193 }
00194 }
00195
00196 return mainfunc;
00197 }
00198
00199
00200 void
00201 function_inline::insert_proc(procNode * m)
00202 {
00203 _procs.insert(m);
00204 }
00205
00206
00207
00208
00209 void
00210 function_inline::process(callGraph & cg)
00211 {
00212
00213 int size = 0;
00214
00215
00216
00217
00218
00219
00220 bool changed = false;
00221
00222
00223
00224
00225 #if DEBUG
00226 cout <<"in process" << endl;
00227 #endif
00228
00229
00230 while(!_procs.empty())
00231 {
00232
00233 proc_set_p p = _procs.begin();
00234 while ( p!= _procs.end())
00235 {
00236
00237
00238
00239
00240 callGraphNode * cgn = cg.lookup(*p);
00241
00242
00243
00244
00245 if(cgn->calls().size()==size || already_inlined_calls(cgn))
00246 {
00247 #if DEBUG
00248 cout << "going to function inliner "<< (*p)->decl()->name() <<endl;
00249 #endif
00250
00251 (*p)->change(*this);
00252 #if DEBUG
00253 cout << "inserting" << (*p)->decl()->name() << endl;
00254 #endif
00255
00256
00257
00258 _inlined.insert(*p);
00259
00260
00261
00262
00263 proc_set_p tmp = p;
00264 p++;
00265 _procs.erase(tmp);
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 if(size!=0)
00276 {
00277 p = _procs.begin();
00278 size = 0;
00279 }
00280 else
00281 changed = true;
00282 }
00283
00284 else
00285 p++;
00286 }
00287
00288 if(!changed)
00289 size++;
00290 else
00291 changed=false;
00292 }
00293
00294 #if DEBUG
00295 cout << "leaving process" << endl;
00296 #endif
00297 }
00298
00299
00300
00301
00302
00303 bool
00304 function_inline::already_inlined_calls(callGraphNode * cgn)
00305 {
00306
00307 #if DEBUG
00308 cout << "in already_inlined_calls"<<endl;
00309 #endif
00310
00311
00312 const callgraph_edge_list & cgel = cgn->calls();
00313
00314
00315 if(cgel.begin()==cgel.end())
00316 {
00317 #if DEBUG
00318 cout << "empty list, returning true"<< endl;
00319 #endif
00320 return true;
00321 }
00322
00323
00324 for(callgraph_edge_list_cp p = cgel.begin(); p != cgel.end(); p++)
00325 {
00326 callGraphNode * checkinline = *p;
00327
00328
00329 procNode * procinline = checkinline->proc();
00330 #if DEBUG
00331 cout << procinline->decl()->name() << endl;
00332 #endif
00333
00334
00335
00336
00337 if(_inlined.find(procinline)==_inlined.end())
00338 return false;
00339 }
00340
00341
00342 return true;
00343 }
00344
00345
00346
00347
00348
00349 Node *
00350 function_inline::at_proc(procNode * p, Order ord)
00351 {
00352 #if DEBUG
00353 cout <<"inside at_proc" << endl;
00354 #endif
00355
00356 if(ord == Preorder)
00357 _callstack.push_front(p);
00358 else
00359 _callstack.pop_front();
00360
00361 #if DEBUG
00362 cout <<"leaving at_proc" << endl;
00363 #endif
00364
00365 return p;
00366 }
00367
00368
00369
00370
00371
00372
00373 Node *
00374 function_inline::at_threeAddr(threeAddrNode * ta, Order ord)
00375 {
00376
00377
00378 if(ord==Postorder)
00379 return ta;
00380
00381 #if DEBUG
00382 cout << "in threeAddr" << endl;
00383 #endif
00384
00385
00386 stmtNode * s=NULL;
00387
00388
00389
00390
00391
00392
00393
00394
00395 if(ta->op()==NULL)
00396 return ta;
00397
00398
00399 if (ta->op()->id()==Operator::FUNC_CALL)
00400 {
00401
00402
00403
00404 operandNode * o = (operandNode *) ta->rhs1();
00405 indexNode * i = o->var();
00406
00407 assert(i->typ()==Id);
00408 idNode * call = (idNode *)i;
00409 declNode * decl = call->decl();
00410 procNode * proc = _procmap[decl];
00411
00412
00413 if (proc)
00414 {
00415 bool inlineit=false;
00416
00417
00418
00419
00420 if(_callinline.find(ta)!=_callinline.end())
00421 {
00422
00423 _localcallstack.clear();
00424 _localcallstack == _callstack;
00425
00426 inlineit = true;
00427 }
00428 else if(!inlocalstack(proc))
00429 {
00430 inlineit = true;
00431 }
00432
00433 if(inlineit)
00434 {
00435 _localcallstack.push_front(proc);
00436
00437 s = inliner(call, proc, ta);
00438
00439 return s;
00440 }
00441 }
00442 }
00443
00444
00445 #if DEBUG
00446 cout << " no inlining leaving threeAddr" << endl;
00447 #endif
00448 return ta;
00449 }
00450
00451
00452 bool
00453 function_inline::inlocalstack(procNode *p)
00454 {
00455 #if DEBUG
00456 cout << "in inlocalstack" << endl;
00457 #endif
00458 for(int i = 0; i < _localcallstack.size(); i++)
00459 {
00460 if((_localcallstack[i])->decl()->name()==p->decl()->name())
00461 return true;
00462 }
00463 return false;
00464 }
00465
00466
00467 stmtNode *
00468 function_inline::inliner(idNode * call, procNode * proc,
00469 threeAddrNode * callsite)
00470 {
00471
00476
00477 procNode * dup_proc = (procNode *) ref_clone_changer::clone(proc, false);
00478
00481
00482 basicblockNode * exit = dup_proc->exit();
00483 blockNode * body = dup_proc->get_body();
00484
00488
00490
00491 funcNode * fd = (funcNode *) dup_proc->decl()->type();
00492 decl_list & formal_args = fd->args();
00493
00495
00496 decl_list & topdecls = body->decls();
00497
00499
00500 threeAddrNode * dup_callsite = (threeAddrNode *)
00501 ref_clone_changer::clone(callsite, false);
00502 operand_list & actual_args = dup_callsite->arg_list();
00503
00504
00505 if (!fd->is_void_args())
00506 {
00507 operand_list::reverse_iterator actuals;
00508 decl_list::reverse_iterator formals;
00509
00510 for(actuals = actual_args.rbegin(), formals = formal_args.rbegin();
00511 actuals!=actual_args.rend() && formals!=formal_args.rend();
00512 actuals++, formals++)
00513 {
00514 declNode * one_arg = *formals;
00515 operandNode * one_act = *actuals;
00516
00518
00519 one_arg->init(one_act);
00520
00522
00523 one_arg->decl_location(declNode::BLOCK);
00524
00525 topdecls.push_front(one_arg);
00526
00527 }
00528 }
00529
00533
00534 returnNode * ret = (returnNode *) exit->stmts().back();
00535 exit->stmts().pop_back();
00536
00537 assert(ret->typ() == Return);
00538
00541 if(proc->return_decl())
00542 {
00543 cout << "return_decl non-null for "<< proc->decl()->name()<<endl;
00544 }
00545 if (proc->return_decl() && callsite->lhs())
00546
00547 {
00548
00550 declNode * retDecl = dup_proc->return_decl();
00551 idNode * returned_id = new idNode(retDecl);
00552
00554
00555 threeAddrNode * bin = (threeAddrNode *) callsite;
00556 operandNode * lhs = (operandNode *)
00557 ref_clone_changer::clone(bin->lhs(), false);
00558
00561
00562 operandNode * rhs = new operandNode(returned_id);
00563 threeAddrNode * assignment =
00564 new threeAddrNode(lhs, rhs, call->coord());
00565 exit->stmts().push_back(assignment);
00566 }
00567
00568 return body;
00569
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579 void
00580 identify_inlinees::at_threeAddr(threeAddrNode * call, Order ord)
00581 {
00582 if (call->op() && call->op()->id()==Operator::FUNC_CALL)
00583 {
00584
00585 operandNode * o = (operandNode *) call->rhs1();
00586 indexNode * i = o->var();
00587 assert(i->typ()==Id);
00588 idNode * c = (idNode *)i;
00589 declNode * decl = c->decl();
00590 procNode * proc = _procmap[decl];
00591 if (proc)
00592 {
00593 funcNode * func = (funcNode *) proc->decl()->type();
00594 if(func->type_qualifiers() & typeNode::INLINE)
00595 {
00596 _callinline.insert(call);
00597 _procs.insert(proc);
00598 }
00599 else
00600 {
00601 _inlined.insert(proc);
00602 }
00603 }
00604
00605 }
00606 }
00607