00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "system.h"
00023
00024 #include "rtl.h"
00025 #include "regs.h"
00026 #include "function.h"
00027 #include "hard-reg-set.h"
00028 #include "flags.h"
00029 #include "insn-config.h"
00030 #include "recog.h"
00031 #include "basic-block.h"
00032 #include "output.h"
00033 #include "except.h"
00034 #include "tree.h"
00035
00036
00037
00038
00039 static rtx return_value_pseudo;
00040
00041 static int identify_call_return_value PARAMS ((rtx, rtx *, rtx *));
00042 static rtx skip_copy_to_return_value PARAMS ((rtx));
00043 static rtx skip_use_of_return_value PARAMS ((rtx, enum rtx_code));
00044 static rtx skip_stack_adjustment PARAMS ((rtx));
00045 static rtx skip_pic_restore PARAMS ((rtx));
00046 static rtx skip_jump_insn PARAMS ((rtx));
00047 static int call_ends_block_p PARAMS ((rtx, rtx));
00048 static int uses_addressof PARAMS ((rtx));
00049 static int sequence_uses_addressof PARAMS ((rtx));
00050 static void purge_reg_equiv_notes PARAMS ((void));
00051 static void purge_mem_unchanging_flag PARAMS ((rtx));
00052 static rtx skip_unreturned_value PARAMS ((rtx));
00053
00054
00055
00056
00057
00058
00059 static int
00060 identify_call_return_value (cp, p_hard_return, p_soft_return)
00061 rtx cp;
00062 rtx *p_hard_return, *p_soft_return;
00063 {
00064 rtx insn, set, hard, soft;
00065
00066 insn = XEXP (cp, 0);
00067
00068 while (NEXT_INSN (insn))
00069 insn = NEXT_INSN (insn);
00070 while (GET_CODE (insn) != CALL_INSN)
00071 insn = PREV_INSN (insn);
00072
00073
00074
00075
00076 if (GET_CODE (PATTERN (insn)) == SET
00077 && GET_CODE (SET_SRC (PATTERN (insn))) == CALL)
00078 hard = SET_DEST (PATTERN (insn));
00079 else if (GET_CODE (PATTERN (insn)) == PARALLEL
00080 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
00081 && GET_CODE (SET_SRC (XVECEXP (PATTERN (insn), 0, 0))) == CALL)
00082 hard = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
00083 else
00084 return 0;
00085
00086
00087 if (GET_CODE (hard) != REG)
00088 return 0;
00089
00090
00091 insn = skip_stack_adjustment (insn);
00092 if (! insn)
00093 return 0;
00094
00095
00096 insn = skip_pic_restore (insn);
00097 if (! insn)
00098 return 0;
00099
00100
00101 insn = NEXT_INSN (insn);
00102 if (! insn)
00103 return 0;
00104
00105
00106 set = single_set (insn);
00107 if (! set || SET_SRC (set) != hard)
00108 return 0;
00109
00110 soft = SET_DEST (set);
00111 insn = NEXT_INSN (insn);
00112
00113
00114
00115
00116 if (insn
00117 && (set = single_set (insn)) != NULL_RTX
00118 && SET_SRC (set) == soft)
00119 {
00120 soft = SET_DEST (set);
00121 insn = NEXT_INSN (insn);
00122 }
00123
00124
00125 if (GET_CODE (soft) != REG || REGNO (soft) < FIRST_PSEUDO_REGISTER)
00126 return 0;
00127
00128
00129 if (reg_set_between_p (soft, insn, NULL_RTX))
00130 return 0;
00131
00132 *p_hard_return = hard;
00133 *p_soft_return = soft;
00134
00135 return 1;
00136 }
00137
00138
00139
00140
00141
00142 static rtx
00143 skip_copy_to_return_value (orig_insn)
00144 rtx orig_insn;
00145 {
00146 rtx insn, set = NULL_RTX;
00147 rtx hardret, softret;
00148
00149
00150 if (! identify_call_return_value (PATTERN (orig_insn), &hardret, &softret))
00151 return orig_insn;
00152
00153 insn = next_nonnote_insn (orig_insn);
00154 if (! insn)
00155 return orig_insn;
00156
00157 set = single_set (insn);
00158 if (! set)
00159 return orig_insn;
00160
00161 if (return_value_pseudo)
00162 {
00163 if (SET_DEST (set) == return_value_pseudo
00164 && SET_SRC (set) == softret)
00165 return insn;
00166 return orig_insn;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 #ifndef OUTGOING_REGNO
00178 #define OUTGOING_REGNO(N) (N)
00179 #endif
00180
00181 if (SET_DEST (set) == current_function_return_rtx
00182 && REG_P (SET_DEST (set))
00183 && OUTGOING_REGNO (REGNO (SET_DEST (set))) == REGNO (hardret)
00184 && SET_SRC (set) == softret)
00185 return insn;
00186
00187
00188
00189
00190
00191 if (REG_P (SET_DEST (set))
00192 && SET_SRC (set) == softret)
00193 {
00194 rtx x = SET_DEST (set);
00195
00196 insn = next_nonnote_insn (insn);
00197 if (! insn)
00198 return orig_insn;
00199
00200 set = single_set (insn);
00201 if (! set)
00202 return orig_insn;
00203
00204 if (SET_DEST (set) == current_function_return_rtx
00205 && REG_P (SET_DEST (set))
00206 && OUTGOING_REGNO (REGNO (SET_DEST (set))) == REGNO (hardret)
00207 && SET_SRC (set) == x)
00208 return insn;
00209 }
00210
00211
00212
00213 return orig_insn;
00214 }
00215
00216
00217
00218
00219 static rtx
00220 skip_use_of_return_value (orig_insn, code)
00221 rtx orig_insn;
00222 enum rtx_code code;
00223 {
00224 rtx insn;
00225
00226 insn = next_nonnote_insn (orig_insn);
00227
00228 if (insn
00229 && GET_CODE (insn) == INSN
00230 && GET_CODE (PATTERN (insn)) == code
00231 && (XEXP (PATTERN (insn), 0) == current_function_return_rtx
00232 || XEXP (PATTERN (insn), 0) == const0_rtx))
00233 return insn;
00234
00235 return orig_insn;
00236 }
00237
00238
00239
00240 static rtx
00241 skip_unreturned_value (orig_insn)
00242 rtx orig_insn;
00243 {
00244 rtx insn = next_nonnote_insn (orig_insn);
00245
00246
00247 if (insn
00248 && GET_CODE (insn) == INSN
00249 && GET_CODE (PATTERN (insn)) == CLOBBER
00250 && REG_P (XEXP (PATTERN (insn), 0))
00251 && (REGNO (XEXP (PATTERN (insn), 0)) >= FIRST_PSEUDO_REGISTER))
00252 {
00253 rtx set_insn = next_nonnote_insn (insn);
00254 rtx set;
00255 if (!set_insn)
00256 return insn;
00257 set = single_set (set_insn);
00258 if (!set
00259 || SET_SRC (set) != XEXP (PATTERN (insn), 0)
00260 || SET_DEST (set) != current_function_return_rtx)
00261 return insn;
00262 return set_insn;
00263 }
00264 return orig_insn;
00265 }
00266
00267
00268
00269
00270
00271 static rtx
00272 skip_stack_adjustment (orig_insn)
00273 rtx orig_insn;
00274 {
00275 rtx insn, set = NULL_RTX;
00276
00277 insn = next_nonnote_insn (orig_insn);
00278
00279 if (insn)
00280 set = single_set (insn);
00281
00282 if (insn
00283 && set
00284 && GET_CODE (SET_SRC (set)) == PLUS
00285 && XEXP (SET_SRC (set), 0) == stack_pointer_rtx
00286 && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
00287 && SET_DEST (set) == stack_pointer_rtx)
00288 return insn;
00289
00290 return orig_insn;
00291 }
00292
00293
00294
00295
00296 static rtx
00297 skip_pic_restore (orig_insn)
00298 rtx orig_insn;
00299 {
00300 rtx insn, set = NULL_RTX;
00301
00302 insn = next_nonnote_insn (orig_insn);
00303
00304 if (insn)
00305 set = single_set (insn);
00306
00307 if (insn && set && SET_DEST (set) == pic_offset_table_rtx)
00308 return insn;
00309
00310 return orig_insn;
00311 }
00312
00313
00314
00315
00316 static rtx
00317 skip_jump_insn (orig_insn)
00318 rtx orig_insn;
00319 {
00320 rtx insn;
00321
00322 insn = next_nonnote_insn (orig_insn);
00323
00324 if (insn
00325 && GET_CODE (insn) == JUMP_INSN
00326 && any_uncondjump_p (insn))
00327 return insn;
00328
00329 return orig_insn;
00330 }
00331
00332
00333
00334
00335 static int
00336 call_ends_block_p (insn, end)
00337 rtx insn;
00338 rtx end;
00339 {
00340 rtx new_insn;
00341
00342 end = next_nonnote_insn (PREV_INSN (end));
00343
00344
00345 if (insn == end)
00346 return 1;
00347
00348
00349
00350
00351 new_insn = skip_copy_to_return_value (insn);
00352
00353
00354
00355
00356 if (return_value_pseudo && insn == new_insn)
00357 return 0;
00358 insn = new_insn;
00359
00360 if (insn == end)
00361 return 1;
00362
00363
00364 insn = skip_stack_adjustment (insn);
00365 if (insn == end)
00366 return 1;
00367
00368
00369 insn = skip_use_of_return_value (insn, CLOBBER);
00370 if (insn == end)
00371 return 1;
00372
00373
00374 insn = skip_unreturned_value (insn);
00375 if (insn == end)
00376 return 1;
00377
00378
00379 insn = skip_use_of_return_value (insn, USE);
00380 if (insn == end)
00381 return 1;
00382
00383
00384
00385 insn = skip_jump_insn (insn);
00386 return insn == end;
00387 }
00388
00389
00390
00391
00392
00393
00394 static int
00395 uses_addressof (x)
00396 rtx x;
00397 {
00398 RTX_CODE code;
00399 int i, j;
00400 const char *fmt;
00401
00402 if (x == NULL_RTX)
00403 return 0;
00404
00405 code = GET_CODE (x);
00406
00407 if (code == ADDRESSOF || x == current_function_internal_arg_pointer)
00408 return 1;
00409
00410 if (code == MEM)
00411 return 0;
00412
00413
00414 fmt = GET_RTX_FORMAT (code);
00415 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
00416 {
00417 if (*fmt == 'e')
00418 {
00419 if (uses_addressof (XEXP (x, i)))
00420 return 1;
00421 }
00422 else if (*fmt == 'E')
00423 {
00424 for (j = 0; j < XVECLEN (x, i); j++)
00425 if (uses_addressof (XVECEXP (x, i, j)))
00426 return 1;
00427 }
00428 }
00429 return 0;
00430 }
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 static int
00442 sequence_uses_addressof (seq)
00443 rtx seq;
00444 {
00445 rtx insn;
00446
00447 for (insn = seq; insn; insn = NEXT_INSN (insn))
00448 if (INSN_P (insn))
00449 {
00450
00451
00452 if (GET_CODE (insn) == CALL_INSN
00453 && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
00454 {
00455 if (XEXP (PATTERN (insn), 0) != NULL_RTX
00456 && sequence_uses_addressof (XEXP (PATTERN (insn), 0)))
00457 return 1;
00458 if (XEXP (PATTERN (insn), 1) != NULL_RTX
00459 && sequence_uses_addressof (XEXP (PATTERN (insn), 1)))
00460 return 1;
00461 if (XEXP (PATTERN (insn), 2) != NULL_RTX
00462 && sequence_uses_addressof (XEXP (PATTERN (insn), 2)))
00463 return 1;
00464 }
00465 else if (uses_addressof (PATTERN (insn))
00466 || (REG_NOTES (insn) && uses_addressof (REG_NOTES (insn))))
00467 return 1;
00468 }
00469 return 0;
00470 }
00471
00472
00473
00474 static void
00475 purge_reg_equiv_notes ()
00476 {
00477 rtx insn;
00478
00479 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
00480 {
00481 while (1)
00482 {
00483 rtx note = find_reg_note (insn, REG_EQUIV, 0);
00484 if (note)
00485 {
00486
00487
00488 remove_note (insn, note);
00489 continue;
00490 }
00491 break;
00492 }
00493 }
00494 }
00495
00496
00497
00498 static void
00499 purge_mem_unchanging_flag (x)
00500 rtx x;
00501 {
00502 RTX_CODE code;
00503 int i, j;
00504 const char *fmt;
00505
00506 if (x == NULL_RTX)
00507 return;
00508
00509 code = GET_CODE (x);
00510
00511 if (code == MEM)
00512 {
00513 if (RTX_UNCHANGING_P (x)
00514 && (XEXP (x, 0) == current_function_internal_arg_pointer
00515 || (GET_CODE (XEXP (x, 0)) == PLUS
00516 && XEXP (XEXP (x, 0), 0) ==
00517 current_function_internal_arg_pointer
00518 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
00519 RTX_UNCHANGING_P (x) = 0;
00520 return;
00521 }
00522
00523
00524 fmt = GET_RTX_FORMAT (code);
00525 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
00526 {
00527 if (*fmt == 'e')
00528 purge_mem_unchanging_flag (XEXP (x, i));
00529 else if (*fmt == 'E')
00530 for (j = 0; j < XVECLEN (x, i); j++)
00531 purge_mem_unchanging_flag (XVECEXP (x, i, j));
00532 }
00533 }
00534
00535
00536
00537
00538 void
00539 replace_call_placeholder (insn, use)
00540 rtx insn;
00541 sibcall_use_t use;
00542 {
00543 if (use == sibcall_use_tail_recursion)
00544 emit_insn_before (XEXP (PATTERN (insn), 2), insn);
00545 else if (use == sibcall_use_sibcall)
00546 emit_insn_before (XEXP (PATTERN (insn), 1), insn);
00547 else if (use == sibcall_use_normal)
00548 emit_insn_before (XEXP (PATTERN (insn), 0), insn);
00549 else
00550 abort ();
00551
00552
00553
00554
00555 if (XEXP (PATTERN (insn), 3))
00556 LABEL_PRESERVE_P (XEXP (PATTERN (insn), 3)) = 0;
00557
00558
00559 remove_insn (insn);
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 void
00572 optimize_sibling_and_tail_recursive_calls ()
00573 {
00574 rtx insn, insns;
00575 basic_block alternate_exit = EXIT_BLOCK_PTR;
00576 bool no_sibcalls_this_function = false;
00577 bool successful_replacement = false;
00578 bool replaced_call_placeholder = false;
00579 edge e;
00580
00581 insns = get_insns ();
00582
00583 cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_PRE_LOOP);
00584
00585
00586 if (n_basic_blocks == 0)
00587 return;
00588
00589
00590
00591
00592 if (USING_SJLJ_EXCEPTIONS && current_function_has_exception_handlers ())
00593 no_sibcalls_this_function = true;
00594
00595 return_value_pseudo = NULL_RTX;
00596
00597
00598
00599
00600
00601
00602 for (e = EXIT_BLOCK_PTR->pred;
00603 e && alternate_exit == EXIT_BLOCK_PTR;
00604 e = e->pred_next)
00605 {
00606 rtx insn;
00607
00608 if (e->dest != EXIT_BLOCK_PTR || e->succ_next != NULL)
00609 continue;
00610
00611
00612
00613 for (insn = EXIT_BLOCK_PTR->prev_bb->head;
00614 insn;
00615 insn = NEXT_INSN (insn))
00616 {
00617 rtx set;
00618
00619 if (GET_CODE (insn) == CODE_LABEL)
00620 continue;
00621
00622 if (GET_CODE (insn) == NOTE)
00623 continue;
00624
00625 if (GET_CODE (insn) == INSN
00626 && GET_CODE (PATTERN (insn)) == USE)
00627 continue;
00628
00629
00630
00631 if (GET_CODE (insn) == INSN
00632 && (set = single_set (insn))
00633 && SET_DEST (set) == current_function_return_rtx
00634 && REG_P (SET_SRC (set))
00635 && !return_value_pseudo)
00636 {
00637 return_value_pseudo = SET_SRC (set);
00638 continue;
00639 }
00640
00641 break;
00642 }
00643
00644
00645
00646
00647 if (insn == NULL)
00648 alternate_exit = e->src;
00649 else
00650 return_value_pseudo = NULL;
00651 }
00652
00653
00654
00655 no_sibcalls_this_function |= sequence_uses_addressof (insns);
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666 for (insn = insns; insn; insn = NEXT_INSN (insn))
00667 {
00668 if (GET_CODE (insn) == CALL_INSN
00669 && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
00670 {
00671 int sibcall = (XEXP (PATTERN (insn), 1) != NULL_RTX);
00672 int tailrecursion = (XEXP (PATTERN (insn), 2) != NULL_RTX);
00673 basic_block call_block = BLOCK_FOR_INSN (insn);
00674
00675
00676
00677
00678
00679 if (current_function_calls_alloca || current_function_stdarg)
00680 sibcall = 0;
00681
00682
00683
00684
00685 if (no_sibcalls_this_function
00686
00687 || frame_offset
00688
00689
00690
00691 || current_function_calls_setjmp
00692
00693
00694
00695 || call_block->succ == NULL
00696 || call_block->succ->succ_next != NULL
00697 || (call_block->succ->dest != EXIT_BLOCK_PTR
00698 && call_block->succ->dest != alternate_exit)
00699
00700
00701 || ! call_ends_block_p (insn, call_block->end))
00702 sibcall = 0, tailrecursion = 0;
00703
00704
00705
00706
00707
00708 if (sibcall || tailrecursion)
00709 successful_replacement = true;
00710 replaced_call_placeholder = true;
00711
00712 replace_call_placeholder (insn,
00713 tailrecursion != 0
00714 ? sibcall_use_tail_recursion
00715 : sibcall != 0
00716 ? sibcall_use_sibcall
00717 : sibcall_use_normal);
00718 }
00719 }
00720
00721 if (successful_replacement)
00722 {
00723 rtx insn;
00724 tree arg;
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736 purge_reg_equiv_notes ();
00737
00738
00739
00740
00741
00742
00743
00744 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
00745 {
00746 if (INSN_P (insn))
00747 purge_mem_unchanging_flag (PATTERN (insn));
00748 }
00749
00750
00751
00752 for (arg = DECL_ARGUMENTS (current_function_decl);
00753 arg;
00754 arg = TREE_CHAIN (arg))
00755 {
00756 if (REG_P (DECL_RTL (arg)))
00757 RTX_UNCHANGING_P (DECL_RTL (arg)) = false;
00758 }
00759 }
00760
00761
00762
00763
00764 if (replaced_call_placeholder)
00765 reorder_blocks ();
00766
00767
00768 free_basic_block_vars (0);
00769 free_EXPR_LIST_list (&tail_recursion_label_list);
00770 }