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
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 #ifdef USE_PCH
00089 #include "opt_pch.h"
00090 #endif // USE_PCH
00091 #pragma hdrstop
00092
00093
00094 #ifdef _KEEP_RCS_ID
00095 #define opt_tail_CXX "opt_tail.cxx"
00096 static char *rcs_id = opt_tail_CXX"$Revision: 1.5 $";
00097 #endif
00098
00099 #include "opt_tail.h"
00100
00101 #include "defs.h"
00102 #include "errors.h"
00103 #include "erglob.h"
00104 #include "mempool.h"
00105 #include "tracing.h"
00106 #include "cxx_memory.h"
00107
00108 #include "opt_sys.h"
00109 #include "opt_cfg.h"
00110 #include "opt_defs.h"
00111 #include "bb_node_set.h"
00112 #include "opt_sym.h"
00113 #include "ttype.h"
00114 #include "wn.h"
00115 #include "config.h"
00116 #include "stab.h"
00117
00118
00119
00120
00121
00122
00123 OPT_TAIL::OPT_TAIL(CFG *cfg, OPT_STAB *opt_stab)
00124 {
00125 _cfg = cfg;
00126 _opt_stab = opt_stab;
00127 _entry_bb = _label_bb = NULL;
00128 _entry_wn = _call_wn = _ret_ldid_wn = _ret_ldid_wn1 =
00129 _ret_stid_wn = _ret_stid_wn1 = _top_label = NULL;
00130
00131 OPT_POOL_Push(_cfg->Loc_pool(), TAIL_TRACE_FLAG );
00132
00133 _do_trace = Get_Trace(TP_GLOBOPT, TAIL_TRACE_FLAG);
00134
00135 if (_do_trace) {
00136 fprintf(TFile, "%sCFG on entry to tail recursion\n%s", DBar, DBar);
00137 _cfg->Print(TFile);
00138 }
00139 }
00140
00141
00142
00143
00144
00145
00146 OPT_TAIL::~OPT_TAIL()
00147 {
00148 OPT_POOL_Pop(_cfg->Loc_pool(), TAIL_TRACE_FLAG);
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 BOOL OPT_TAIL::Entry_is_well_behaved()
00160 {
00161
00162 if (_cfg->Fake_entry_bb() != NULL) {
00163 INT entry_count = 0;
00164 BB_LIST_ITER entry_iter(_cfg->Fake_entry_bb()->Succ());
00165 FOR_ALL_ITEM(entry_iter, Init()) {
00166 BB_NODE *bb = entry_iter.Cur_bb();
00167 if (bb->Kind() == BB_ENTRY) {
00168 _entry_bb = bb;
00169 entry_count++;
00170 }
00171 }
00172 if (entry_count != 1) {
00173 _entry_bb = NULL;
00174 }
00175 } else {
00176 _entry_bb = _cfg->Func_entry_bb();
00177 }
00178
00179 if (_entry_bb == NULL)
00180 return FALSE;
00181
00182 _entry_wn = NULL;
00183 if (_entry_bb->Kind() == BB_ENTRY)
00184 _entry_wn = _entry_bb->Entrywn();
00185 if (_entry_wn == NULL)
00186 return FALSE;
00187
00188
00189 if (TY_is_varargs(ST_type(WN_st(_entry_wn))))
00190 return FALSE;
00191
00192
00193 INT formal_num;
00194 for (formal_num = 0; formal_num < WN_num_formals(_entry_wn);
00195 formal_num++) {
00196 WN *formal = WN_formal(_entry_wn, formal_num);
00197 TY_IDX formal_type = ST_type(WN_st(formal));
00198 if (MTYPE_is_m(TY_mtype(formal_type)))
00199 return FALSE;
00200 }
00201
00202
00203 BB_NODE *first_bb = _entry_bb;
00204 if (first_bb->Firststmt() != NULL)
00205 return FALSE;
00206
00207
00208 if (first_bb->Succ() == NULL ||
00209 first_bb->Succ()->Next() != NULL)
00210 return FALSE;
00211
00212 first_bb = first_bb->Succ()->Node();
00213
00214
00215
00216
00217 if (first_bb->Pred() == NULL ||
00218 first_bb->Pred()->Next() != NULL)
00219 return FALSE;
00220
00221 return TRUE;
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 BOOL OPT_TAIL::Exit_is_well_behaved(BB_NODE *bb)
00233 {
00234 STMT_CONTAINER bb_stmts(bb->Firststmt(), bb->Laststmt());
00235
00236
00237 WN *stmt_ptr = bb_stmts.Tail();
00238 if (stmt_ptr == NULL ||
00239 (WN_operator(stmt_ptr) != OPR_RETURN &&
00240 WN_operator(stmt_ptr) != OPR_RETURN_VAL)) {
00241 return FALSE;
00242 }
00243
00244 _ret_ldid_wn = _ret_ldid_wn1 = NULL;
00245 _ret_stid_wn = _ret_stid_wn1 = NULL;
00246
00247 while ((stmt_ptr = WN_prev(stmt_ptr)) != NULL) {
00248 if (WN_operator(stmt_ptr) == OPR_CALL) {
00249
00250 _call_wn = stmt_ptr;
00251 if (WN_st(_call_wn) != WN_st(_entry_wn)) {
00252 if (_do_trace)
00253 fprintf(TFile, "-- Doesn't call this function\n");
00254 return FALSE;
00255 }
00256
00257
00258 if ( WN_num_actuals(_call_wn) != WN_num_formals(_entry_wn) ) {
00259 if (_do_trace)
00260 fprintf(TFile,
00261 "-- Number of actuals (%d) != number of formals (%d)\n",
00262 WN_num_actuals(_call_wn), WN_num_formals(_entry_wn) );
00263 return FALSE;
00264 }
00265
00266 break;
00267 }
00268
00269
00270 if (WN_operator(stmt_ptr) != OPR_STID ||
00271 WN_operator(WN_kid0(stmt_ptr)) != OPR_LDID) {
00272 if (_do_trace)
00273 fprintf(TFile, "-- Instruction not stid or ldid\n");
00274 return FALSE;
00275 }
00276 ST *stid_st = _opt_stab->St((IDTYPE)WN_st_idx(stmt_ptr));
00277 if (ST_class(stid_st) == CLASS_PREG &&
00278 Preg_Is_Dedicated(WN_store_offset(stmt_ptr))) {
00279 if (_ret_stid_wn == NULL)
00280 _ret_stid_wn = stmt_ptr;
00281 else if (_ret_stid_wn1 == NULL)
00282 _ret_stid_wn1 = stmt_ptr;
00283 else {
00284 if (_do_trace)
00285 fprintf(TFile, "-- Found more than two stid into dedpreg\n");
00286 return FALSE;
00287 }
00288 continue;
00289 }
00290 ST *ldid_st = _opt_stab->St((IDTYPE)WN_st_idx(WN_kid0(stmt_ptr)));
00291 if (ST_class(ldid_st) == CLASS_PREG &&
00292 Preg_Is_Dedicated(WN_load_offset(WN_kid0(stmt_ptr)))) {
00293 if (_ret_ldid_wn == NULL)
00294 _ret_ldid_wn = stmt_ptr;
00295 else if (_ret_ldid_wn1 == NULL)
00296 _ret_ldid_wn1 = stmt_ptr;
00297 else {
00298 if (_do_trace)
00299 fprintf(TFile, "-- Found more than two ldid from dedpreg\n");
00300 return FALSE;
00301 }
00302 continue;
00303 }
00304 if (_do_trace)
00305 fprintf(TFile, "-- Instruction not stid into dedpreg or stid of ldid from dedpreg\n");
00306 return FALSE;
00307 }
00308
00309 if (stmt_ptr == NULL)
00310 return FALSE;
00311
00312
00313 INT formal_num;
00314 for (formal_num = 0; formal_num < WN_num_actuals(_call_wn);
00315 formal_num++)
00316 {
00317 WN *formal = WN_formal(_entry_wn, formal_num);
00318 Is_True(WN_operator(formal) == OPR_IDNAME,
00319 ("formal is not IDNAME"));
00320 ST *formal_st = WN_st(formal);
00321 TYPE_ID formal_type_id = TY_mtype(ST_type(formal_st));
00322
00323 WN *arg = WN_actual(_call_wn, formal_num);
00324 const OPCODE arg_opc = WN_opcode(arg);
00325 const OPERATOR arg_opr = OPCODE_operator(arg_opc);
00326 Is_True( arg_opr == OPR_PARM,
00327 ("Call parameter not OPR_PARM"));
00328 TYPE_ID arg_type_id = OPCODE_rtype(arg_opc);
00329
00330 if (formal_type_id != arg_type_id) {
00331 if (_do_trace)
00332 fprintf(TFile, "-- Argument %d not proper type\n", formal_num);
00333 return FALSE;
00334 }
00335
00336
00337
00338 WN *arg_kid = WN_kid0(arg);
00339 const OPERATOR arg_kid_opr = WN_operator(arg_kid);
00340 if ( arg_kid_opr == OPR_LDA ) {
00341 ST *lda_st = _opt_stab->St((IDTYPE)WN_st_idx(arg_kid));
00342 if ( ST_class(lda_st) == CLASS_VAR ) {
00343 if (ST_sclass(lda_st) == SCLASS_AUTO ||
00344 ST_sclass(lda_st) == SCLASS_FORMAL)
00345 {
00346 if (_do_trace)
00347 fprintf( TFile, "-- Argument %d is lda of local\n",
00348 formal_num );
00349 return FALSE;
00350 }
00351 }
00352 }
00353
00354 }
00355
00356 return TRUE;
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 void OPT_TAIL::Create_top_label()
00368 {
00369 BB_NODE *first_bb = _entry_bb->Succ()->Node();
00370 WN *last_copy = NULL;
00371
00372 for ( WN *tmp_wn = first_bb->Firststmt();
00373 tmp_wn != NULL;
00374 tmp_wn = WN_next(tmp_wn) )
00375 {
00376 if ( WN_operator(tmp_wn) != OPR_STID )
00377 break;
00378
00379
00380 WN *load_wn = WN_kid0(tmp_wn);
00381 if (WN_operator(load_wn) == OPR_CVTL ||
00382 WN_operator(load_wn) == OPR_CVT)
00383 load_wn = WN_kid0(load_wn);
00384
00385 if (WN_operator(load_wn) != OPR_LDID)
00386 break;
00387
00388 if (ST_class(_opt_stab->St(WN_aux(load_wn))) != CLASS_PREG ||
00389 !Preg_Is_Dedicated(WN_load_offset(load_wn)))
00390 break;
00391
00392
00393
00394
00395 last_copy = tmp_wn;
00396 }
00397
00398 if (_do_trace) {
00399 fprintf(TFile, "Last arg copy is:\n");
00400 fdump_tree_no_st(TFile, last_copy);
00401 }
00402
00403
00404 _label_bb = NULL;
00405 if ( last_copy == NULL ) {
00406 _label_bb = first_bb;
00407 } else {
00408 BOOL has_call = first_bb->Hascall();
00409 _label_bb = _cfg->Split_bb_with_wns(first_bb, last_copy);
00410 first_bb->Reset_hascall();
00411 _label_bb->Reset_hascall();
00412 if (has_call)
00413 first_bb->Set_hascall();
00414 }
00415
00416
00417 _top_label = _label_bb->Label_wn();
00418 if (_top_label == NULL) {
00419 _top_label = WN_CreateLabel(0, _cfg->Alloc_label(), 0, NULL);
00420 _cfg->Prepend_wn_in(_label_bb, _top_label);
00421 _cfg->Append_label_map(WN_label_number(_top_label), _label_bb);
00422 }
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432 void OPT_TAIL::Fixup_exit(BB_NODE *bb)
00433 {
00434 STMT_CONTAINER bb_stmts(bb->Firststmt(), bb->Laststmt());
00435
00436
00437 bb_stmts.Remove(_call_wn);
00438
00439
00440 if (_ret_stid_wn)
00441 bb_stmts.Remove(_ret_stid_wn);
00442 if (_ret_stid_wn1)
00443 bb_stmts.Remove(_ret_stid_wn1);
00444 if (_ret_ldid_wn)
00445 bb_stmts.Remove(_ret_ldid_wn);
00446 if (_ret_ldid_wn1)
00447 bb_stmts.Remove(_ret_ldid_wn1);
00448
00449
00450 bb_stmts.Remove(bb_stmts.Tail());
00451
00452
00453
00454
00455
00456
00457 STACK<AUX_ID> preg_stack(_cfg->Loc_pool());
00458
00459 INT formal_num;
00460 for (formal_num = 0; formal_num < WN_num_actuals(_call_wn);
00461 formal_num++)
00462 {
00463 WN *formal = WN_formal(_entry_wn, formal_num);
00464 Is_True(WN_operator(formal) == OPR_IDNAME,
00465 ("formal is not IDNAME"));
00466 AUX_ID formal_id = _opt_stab->
00467 Find_sym_with_st_and_ofst(WN_st(formal),
00468 WN_idname_offset(formal));
00469
00470
00471
00472 if (formal_id == 0) {
00473 continue;
00474 }
00475 WN *arg = WN_actual(_call_wn, formal_num);
00476 Is_True(WN_operator(arg) == OPR_PARM,
00477 ("Call parameter not OPR_PARM"));
00478 TYPE_ID arg_type_id = WN_rtype(arg);
00479
00480 arg = WN_kid0(arg);
00481 #ifdef KEY
00482
00483 static INT Temp_Index = 0;
00484 UINT len = strlen("_temp_") + 17;
00485 #ifdef __MINGW32__
00486 char *new_str = (char *) __builtin_alloca (len);
00487 #else
00488 char *new_str = (char *) alloca (len);
00489 #endif
00490 sprintf(new_str, "%s%d", "_temp_", Temp_Index++);
00491 AUX_ID tmp_preg = _opt_stab->Create_preg(arg_type_id, new_str);
00492 #else
00493 AUX_ID tmp_preg = _opt_stab->Create_preg(arg_type_id);
00494 #endif
00495 WN *stid = WN_CreateStid(OPR_STID, MTYPE_V, arg_type_id,
00496 _opt_stab->St_ofst(tmp_preg),
00497 ST_st_idx(_opt_stab->St(tmp_preg)),
00498 Be_Type_Tbl(arg_type_id), arg);
00499
00500 WN_set_aux(stid, (AUX_ID)tmp_preg);
00501 bb_stmts.Append(stid);
00502
00503 preg_stack.Push(tmp_preg);
00504 }
00505
00506
00507 for (formal_num = WN_num_formals(_entry_wn)-1; formal_num >= 0;
00508 formal_num--) {
00509 WN *formal = WN_formal(_entry_wn, formal_num);
00510 AUX_ID formal_id = _opt_stab->
00511 Find_sym_with_st_and_ofst(WN_st(formal),
00512 WN_idname_offset(formal));
00513
00514
00515
00516 if (formal_id == 0) {
00517 continue;
00518 }
00519 ST *formal_st = WN_st(formal);
00520 TY_IDX formal_type = ST_type(formal_st);
00521
00522 AUX_ID tmp_preg = preg_stack.Pop();
00523 TY_IDX arg_type = ST_type(_opt_stab->St(tmp_preg));
00524 WN *ldid = WN_CreateLdid(OPR_LDID, TY_mtype(arg_type), TY_mtype(arg_type),
00525 _opt_stab->St_ofst(tmp_preg),
00526 ST_st_idx(_opt_stab->St(tmp_preg)), arg_type);
00527
00528 WN_set_aux(ldid, (AUX_ID)tmp_preg);
00529
00530 if (TY_mtype(formal_type) != TY_mtype(arg_type)) {
00531 ldid = WN_CreateExp1(OPCODE_make_op(OPR_CVT, TY_mtype(formal_type),
00532 TY_mtype(arg_type)), ldid);
00533 }
00534
00535 WN *stid = WN_CreateStid(OPR_STID, MTYPE_V, TY_mtype(formal_type),
00536 0, formal_st, formal_type, ldid);
00537
00538 WN_set_aux(stid, formal_id);
00539 bb_stmts.Append(stid);
00540 }
00541
00542
00543 WN *goto_wn = WN_CreateGoto((ST *) NULL, WN_label_number(_top_label));
00544 bb_stmts.Append(goto_wn);
00545
00546
00547 bb->Set_kind(BB_GOTO);
00548 bb->Set_firststmt(bb_stmts.Head());
00549 bb->Set_laststmt(bb_stmts.Tail());
00550
00551
00552 if ( bb->Succ()->Contains( _cfg->Exit_bb() ) ) {
00553 _cfg->DisConnect_predsucc( bb, _cfg->Exit_bb() );
00554 }
00555
00556
00557 _cfg->Connect_predsucc( bb, _label_bb );
00558 }
00559
00560
00561
00562
00563
00564 void OPT_TAIL::Mutate()
00565 {
00566 if (!Entry_is_well_behaved())
00567 return;
00568
00569 CFG_ITER cfg_iter(_cfg);
00570 BB_NODE *bb;
00571
00572 FOR_ALL_NODE(bb, cfg_iter, Init()) {
00573
00574
00575 if ( bb->Kind() != BB_EXIT ) {
00576 continue;
00577 }
00578
00579 if (_do_trace) {
00580 fprintf(TFile, "Considering exit:\n");
00581 bb->Print(TFile);
00582 }
00583
00584 if (Exit_is_well_behaved(bb)) {
00585
00586 if (_top_label == NULL) {
00587 WN *bb_last_stmt = bb->Laststmt();
00588
00589 Create_top_label();
00590
00591
00592 if ( bb_last_stmt != bb->Laststmt() ) {
00593 bb = bb->Next();
00594 }
00595 }
00596
00597
00598 Fixup_exit(bb);
00599
00600 if (_do_trace) {
00601 fprintf(TFile, "New exit is:\n");
00602 bb->Print(TFile);
00603 }
00604 }
00605 }
00606
00607 if (_do_trace) {
00608 fprintf(TFile, "%sCFG on exit from tail recursion\n%s", DBar, DBar);
00609 _cfg->Print(TFile);
00610 }
00611 }