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 #include "config.h"
00029 #include "system.h"
00030 #include "rtl.h"
00031 #include "tm_p.h"
00032 #include "insn-config.h"
00033 #include "recog.h"
00034 #include "output.h"
00035 #include "regs.h"
00036 #include "hard-reg-set.h"
00037 #include "flags.h"
00038 #include "function.h"
00039 #include "expr.h"
00040 #include "basic-block.h"
00041 #include "except.h"
00042 #include "toplev.h"
00043 #include "reload.h"
00044
00045
00046
00047 #ifdef STACK_GROWS_DOWNWARD
00048 #undef STACK_GROWS_DOWNWARD
00049 #define STACK_GROWS_DOWNWARD 1
00050 #else
00051 #define STACK_GROWS_DOWNWARD 0
00052 #endif
00053
00054 static int perhaps_ends_bb_p PARAMS ((rtx));
00055 static int optimize_reg_copy_1 PARAMS ((rtx, rtx, rtx));
00056 static void optimize_reg_copy_2 PARAMS ((rtx, rtx, rtx));
00057 static void optimize_reg_copy_3 PARAMS ((rtx, rtx, rtx));
00058 static void copy_src_to_dest PARAMS ((rtx, rtx, rtx, int));
00059 static int *regmove_bb_head;
00060
00061 struct match {
00062 int with[MAX_RECOG_OPERANDS];
00063 enum { READ, WRITE, READWRITE } use[MAX_RECOG_OPERANDS];
00064 int commutative[MAX_RECOG_OPERANDS];
00065 int early_clobber[MAX_RECOG_OPERANDS];
00066 };
00067
00068 static rtx discover_flags_reg PARAMS ((void));
00069 static void mark_flags_life_zones PARAMS ((rtx));
00070 static void flags_set_1 PARAMS ((rtx, rtx, void *));
00071
00072 static int try_auto_increment PARAMS ((rtx, rtx, rtx, rtx, HOST_WIDE_INT, int));
00073 static int find_matches PARAMS ((rtx, struct match *));
00074 static void replace_in_call_usage PARAMS ((rtx *, unsigned int, rtx, rtx));
00075 static int fixup_match_1 PARAMS ((rtx, rtx, rtx, rtx, rtx, int, int, int, FILE *))
00076 ;
00077 static int reg_is_remote_constant_p PARAMS ((rtx, rtx, rtx));
00078 static int stable_and_no_regs_but_for_p PARAMS ((rtx, rtx, rtx));
00079 static int regclass_compatible_p PARAMS ((int, int));
00080 static int replacement_quality PARAMS ((rtx));
00081 static int fixup_match_2 PARAMS ((rtx, rtx, rtx, rtx, FILE *));
00082
00083
00084
00085 static int
00086 regclass_compatible_p (class0, class1)
00087 int class0, class1;
00088 {
00089 return (class0 == class1
00090 || (reg_class_subset_p (class0, class1)
00091 && ! CLASS_LIKELY_SPILLED_P (class0))
00092 || (reg_class_subset_p (class1, class0)
00093 && ! CLASS_LIKELY_SPILLED_P (class1)));
00094 }
00095
00096
00097
00098
00099
00100 static int
00101 try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
00102 rtx reg, insn, inc_insn ,inc_insn_set;
00103 HOST_WIDE_INT increment;
00104 int pre;
00105 {
00106 enum rtx_code inc_code;
00107
00108 rtx pset = single_set (insn);
00109 if (pset)
00110 {
00111
00112
00113 rtx use = find_use_as_address (pset, reg, 0);
00114 if (use != 0 && use != (rtx) (size_t) 1)
00115 {
00116 int size = GET_MODE_SIZE (GET_MODE (use));
00117 if (0
00118 || (HAVE_POST_INCREMENT
00119 && pre == 0 && (inc_code = POST_INC, increment == size))
00120 || (HAVE_PRE_INCREMENT
00121 && pre == 1 && (inc_code = PRE_INC, increment == size))
00122 || (HAVE_POST_DECREMENT
00123 && pre == 0 && (inc_code = POST_DEC, increment == -size))
00124 || (HAVE_PRE_DECREMENT
00125 && pre == 1 && (inc_code = PRE_DEC, increment == -size))
00126 )
00127 {
00128 if (inc_insn_set)
00129 validate_change
00130 (inc_insn,
00131 &SET_SRC (inc_insn_set),
00132 XEXP (SET_SRC (inc_insn_set), 0), 1);
00133 validate_change (insn, &XEXP (use, 0),
00134 gen_rtx_fmt_e (inc_code, Pmode, reg), 1);
00135 if (apply_change_group ())
00136 {
00137
00138
00139
00140
00141
00142
00143 rtx note = find_reg_note (insn, REG_DEAD, reg);
00144 if (note)
00145 PUT_MODE (note, REG_UNUSED);
00146
00147 REG_NOTES (insn)
00148 = gen_rtx_EXPR_LIST (REG_INC,
00149 reg, REG_NOTES (insn));
00150 if (! inc_insn_set)
00151 delete_insn (inc_insn);
00152 return 1;
00153 }
00154 }
00155 }
00156 }
00157 return 0;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167 static rtx
00168 discover_flags_reg ()
00169 {
00170 rtx tmp;
00171 tmp = gen_rtx_REG (word_mode, 10000);
00172 tmp = gen_add3_insn (tmp, tmp, GEN_INT (2));
00173
00174
00175
00176 if (GET_CODE (tmp) == SET)
00177 return NULL_RTX;
00178 else if (GET_CODE (tmp) == PARALLEL)
00179 {
00180 int found;
00181
00182 if (XVECLEN (tmp, 0) != 2)
00183 return pc_rtx;
00184 tmp = XVECEXP (tmp, 0, 1);
00185 if (GET_CODE (tmp) != CLOBBER)
00186 return pc_rtx;
00187 tmp = XEXP (tmp, 0);
00188
00189
00190
00191
00192 if (GET_CODE (tmp) == SUBREG
00193 && GET_CODE (SUBREG_REG (tmp)) == REG
00194 && REGNO (SUBREG_REG (tmp)) < FIRST_PSEUDO_REGISTER)
00195 return pc_rtx;
00196 found = (GET_CODE (tmp) == REG && REGNO (tmp) < FIRST_PSEUDO_REGISTER);
00197
00198 return (found ? tmp : NULL_RTX);
00199 }
00200
00201 return pc_rtx;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 static rtx flags_set_1_rtx;
00218 static int flags_set_1_set;
00219
00220 static void
00221 mark_flags_life_zones (flags)
00222 rtx flags;
00223 {
00224 int flags_regno;
00225 int flags_nregs;
00226 basic_block block;
00227
00228 #ifdef HAVE_cc0
00229
00230 if (flags == NULL_RTX)
00231 flags = cc0_rtx;
00232 else if (flags != cc0_rtx)
00233 flags = pc_rtx;
00234 #endif
00235
00236
00237
00238 if (flags == NULL_RTX || flags == pc_rtx)
00239 {
00240 enum machine_mode mode = (flags ? HImode : VOIDmode);
00241 rtx insn;
00242 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
00243 PUT_MODE (insn, mode);
00244 return;
00245 }
00246
00247 #ifdef HAVE_cc0
00248 flags_regno = -1;
00249 flags_nregs = 1;
00250 #else
00251 flags_regno = REGNO (flags);
00252 flags_nregs = HARD_REGNO_NREGS (flags_regno, GET_MODE (flags));
00253 #endif
00254 flags_set_1_rtx = flags;
00255
00256
00257 FOR_EACH_BB_REVERSE (block)
00258 {
00259 rtx insn, end;
00260 int live;
00261
00262 insn = block->head;
00263 end = block->end;
00264
00265
00266
00267 live = 0;
00268 #ifndef HAVE_cc0
00269 {
00270 int i;
00271 for (i = 0; i < flags_nregs; ++i)
00272 live |= REGNO_REG_SET_P (block->global_live_at_start,
00273 flags_regno + i);
00274 }
00275 #endif
00276
00277 while (1)
00278 {
00279
00280
00281
00282
00283 if (INSN_P (insn))
00284 {
00285 #ifdef HAVE_cc0
00286
00287
00288 if (live && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
00289 live = 0;
00290 #else
00291
00292 if (live && find_regno_note (insn, REG_DEAD, flags_regno))
00293 live = 0;
00294 #endif
00295 PUT_MODE (insn, (live ? HImode : VOIDmode));
00296
00297
00298
00299 flags_set_1_set = 0;
00300 note_stores (PATTERN (insn), flags_set_1, NULL);
00301 if (flags_set_1_set)
00302 {
00303 live = 1;
00304 PUT_MODE (insn, QImode);
00305 }
00306 }
00307 else
00308 PUT_MODE (insn, (live ? HImode : VOIDmode));
00309
00310 if (insn == end)
00311 break;
00312 insn = NEXT_INSN (insn);
00313 }
00314 }
00315 }
00316
00317
00318
00319 static void
00320 flags_set_1 (x, pat, data)
00321 rtx x, pat;
00322 void *data ATTRIBUTE_UNUSED;
00323 {
00324 if (GET_CODE (pat) == SET
00325 && reg_overlap_mentioned_p (x, flags_set_1_rtx))
00326 flags_set_1_set = 1;
00327 }
00328
00329 static int *regno_src_regno;
00330
00331
00332
00333
00334
00335
00336 static int
00337 replacement_quality (reg)
00338 rtx reg;
00339 {
00340 int src_regno;
00341
00342
00343 if (GET_CODE (reg) != REG)
00344 return 0;
00345
00346
00347
00348 if (REG_LIVE_LENGTH (REGNO (reg)) < 0)
00349 return 0;
00350
00351 src_regno = regno_src_regno[REGNO (reg)];
00352
00353
00354 if (src_regno < 0)
00355 return 3;
00356
00357
00358 if (src_regno < FIRST_PSEUDO_REGISTER)
00359 return 1;
00360
00361
00362
00363
00364 return 2;
00365 }
00366
00367
00368
00369 static int perhaps_ends_bb_p (insn)
00370 rtx insn;
00371 {
00372 switch (GET_CODE (insn))
00373 {
00374 case CODE_LABEL:
00375 case JUMP_INSN:
00376
00377 return 1;
00378
00379 case CALL_INSN:
00380
00381
00382
00383 if (nonlocal_goto_handler_labels)
00384 return 1;
00385
00386 default:
00387 return can_throw_internal (insn);
00388 }
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 static int
00403 optimize_reg_copy_1 (insn, dest, src)
00404 rtx insn;
00405 rtx dest;
00406 rtx src;
00407 {
00408 rtx p, q;
00409 rtx note;
00410 rtx dest_death = 0;
00411 int sregno = REGNO (src);
00412 int dregno = REGNO (dest);
00413
00414
00415 if (sregno == dregno
00416 || (SMALL_REGISTER_CLASSES
00417 && (sregno < FIRST_PSEUDO_REGISTER
00418 || dregno < FIRST_PSEUDO_REGISTER))
00419
00420
00421 || sregno == STACK_POINTER_REGNUM || dregno == STACK_POINTER_REGNUM)
00422 return 0;
00423
00424 for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
00425 {
00426
00427
00428 if (perhaps_ends_bb_p (p))
00429 break;
00430 else if (! INSN_P (p))
00431 continue;
00432
00433 if (reg_set_p (src, p) || reg_set_p (dest, p)
00434
00435
00436
00437
00438
00439
00440
00441 || (sregno < FIRST_PSEUDO_REGISTER
00442 && asm_noperands (PATTERN (p)) >= 0
00443 && reg_overlap_mentioned_p (src, PATTERN (p)))
00444
00445 || (GET_CODE (PATTERN (p)) == USE
00446 && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
00447 break;
00448
00449
00450
00451 if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0
00452 && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
00453 {
00454 int failed = 0;
00455 int d_length = 0;
00456 int s_length = 0;
00457 int d_n_calls = 0;
00458 int s_n_calls = 0;
00459
00460
00461
00462
00463
00464
00465
00466 for (q = next_real_insn (insn);
00467 q != next_real_insn (p);
00468 q = next_real_insn (q))
00469 {
00470 if (reg_overlap_mentioned_p (src, PATTERN (q)))
00471 {
00472
00473
00474
00475
00476
00477 if (sregno < FIRST_PSEUDO_REGISTER
00478 && reg_mentioned_p (dest, PATTERN (q)))
00479 failed = 1;
00480
00481
00482
00483 else if (validate_replace_rtx (src, dest, q)
00484 && (sregno >= FIRST_PSEUDO_REGISTER
00485 || ! reg_overlap_mentioned_p (src,
00486 PATTERN (q))))
00487 ;
00488 else
00489 {
00490 validate_replace_rtx (dest, src, q);
00491 failed = 1;
00492 }
00493 }
00494
00495
00496
00497
00498 s_length++;
00499 if (dest_death)
00500 d_length++;
00501
00502
00503
00504 if (q != p && GET_CODE (q) == CALL_INSN)
00505 {
00506
00507
00508 s_n_calls++;
00509 if (dest_death)
00510 d_n_calls++;
00511 }
00512
00513
00514
00515
00516 if (dest_death == 0
00517 && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0)
00518 {
00519 if (GET_MODE (XEXP (dest_death, 0)) != GET_MODE (dest))
00520 failed = 1, dest_death = 0;
00521 else
00522 remove_note (q, dest_death);
00523 }
00524 }
00525
00526 if (! failed)
00527 {
00528
00529
00530 if (sregno >= FIRST_PSEUDO_REGISTER)
00531 {
00532 if (REG_LIVE_LENGTH (sregno) >= 0)
00533 {
00534 REG_LIVE_LENGTH (sregno) -= s_length;
00535
00536
00537
00538 if (REG_LIVE_LENGTH (sregno) < 2)
00539 REG_LIVE_LENGTH (sregno) = 2;
00540 }
00541
00542 REG_N_CALLS_CROSSED (sregno) -= s_n_calls;
00543 }
00544
00545
00546 remove_note (p, note);
00547 XEXP (note, 1) = REG_NOTES (insn);
00548 REG_NOTES (insn) = note;
00549 }
00550
00551
00552 if (! dest_death
00553 && (dest_death = find_regno_note (insn, REG_UNUSED, dregno)))
00554 {
00555 PUT_REG_NOTE_KIND (dest_death, REG_DEAD);
00556 remove_note (insn, dest_death);
00557 }
00558
00559
00560 if (dest_death)
00561 {
00562 XEXP (dest_death, 1) = REG_NOTES (p);
00563 REG_NOTES (p) = dest_death;
00564
00565 if (dregno >= FIRST_PSEUDO_REGISTER)
00566 {
00567
00568
00569 if (REG_LIVE_LENGTH (dregno) >= 0)
00570 REG_LIVE_LENGTH (dregno) += d_length;
00571 REG_N_CALLS_CROSSED (dregno) += d_n_calls;
00572 }
00573 }
00574
00575 return ! failed;
00576 }
00577
00578
00579
00580 else if (sregno < FIRST_PSEUDO_REGISTER
00581 && dead_or_set_p (p, src))
00582 break;
00583 }
00584 return 0;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 static void
00602 optimize_reg_copy_2 (insn, dest, src)
00603 rtx insn;
00604 rtx dest;
00605 rtx src;
00606 {
00607 rtx p, q;
00608 rtx set;
00609 int sregno = REGNO (src);
00610 int dregno = REGNO (dest);
00611
00612 for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
00613 {
00614
00615
00616 if (perhaps_ends_bb_p (p))
00617 break;
00618 else if (! INSN_P (p))
00619 continue;
00620
00621 set = single_set (p);
00622 if (set && SET_SRC (set) == dest && SET_DEST (set) == src
00623 && find_reg_note (p, REG_DEAD, dest))
00624 {
00625
00626
00627
00628
00629 for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q))
00630 if (INSN_P (q))
00631 {
00632 if (reg_mentioned_p (dest, PATTERN (q)))
00633 PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
00634
00635
00636 if (GET_CODE (q) == CALL_INSN)
00637 {
00638 REG_N_CALLS_CROSSED (dregno)--;
00639 REG_N_CALLS_CROSSED (sregno)++;
00640 }
00641 }
00642
00643 remove_note (p, find_reg_note (p, REG_DEAD, dest));
00644 REG_N_DEATHS (dregno)--;
00645 remove_note (insn, find_reg_note (insn, REG_DEAD, src));
00646 REG_N_DEATHS (sregno)--;
00647 return;
00648 }
00649
00650 if (reg_set_p (src, p)
00651 || find_reg_note (p, REG_DEAD, dest)
00652 || (GET_CODE (p) == CALL_INSN && REG_N_CALLS_CROSSED (sregno) == 0))
00653 break;
00654 }
00655 }
00656
00657
00658
00659
00660
00661
00662 static void
00663 optimize_reg_copy_3 (insn, dest, src)
00664 rtx insn;
00665 rtx dest;
00666 rtx src;
00667 {
00668 rtx src_reg = XEXP (src, 0);
00669 int src_no = REGNO (src_reg);
00670 int dst_no = REGNO (dest);
00671 rtx p, set, subreg;
00672 enum machine_mode old_mode;
00673
00674 if (src_no < FIRST_PSEUDO_REGISTER
00675 || dst_no < FIRST_PSEUDO_REGISTER
00676 || ! find_reg_note (insn, REG_DEAD, src_reg)
00677 || REG_N_DEATHS (src_no) != 1
00678 || REG_N_SETS (src_no) != 1)
00679 return;
00680 for (p = PREV_INSN (insn); p && ! reg_set_p (src_reg, p); p = PREV_INSN (p))
00681
00682
00683 if (perhaps_ends_bb_p (p))
00684 break;
00685
00686 if (! p)
00687 return;
00688
00689 if (! (set = single_set (p))
00690 || GET_CODE (SET_SRC (set)) != MEM
00691
00692
00693 || find_reg_note (p, REG_EQUIV, NULL_RTX)
00694 || SET_DEST (set) != src_reg)
00695 return;
00696
00697
00698
00699 if (MEM_VOLATILE_P (SET_SRC (set)))
00700 return;
00701
00702
00703
00704 if (GET_MODE_BITSIZE (GET_MODE (src_reg)) <= GET_MODE_BITSIZE (GET_MODE (src))
00705 && !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (src)),
00706 GET_MODE_BITSIZE (GET_MODE (src_reg))))
00707 return;
00708
00709 old_mode = GET_MODE (src_reg);
00710 PUT_MODE (src_reg, GET_MODE (src));
00711 XEXP (src, 0) = SET_SRC (set);
00712
00713
00714
00715 validate_change (p, &SET_SRC (set), src, 1);
00716
00717
00718
00719 subreg = gen_lowpart_SUBREG (old_mode, src_reg);
00720 while (p = NEXT_INSN (p), p != insn)
00721 {
00722 if (! INSN_P (p))
00723 continue;
00724
00725
00726 validate_replace_rtx_group (src_reg, subreg, p);
00727 }
00728
00729 validate_replace_rtx_group (src, src_reg, insn);
00730
00731
00732 if (! apply_change_group ())
00733 {
00734
00735 PUT_MODE (src_reg, old_mode);
00736 XEXP (src, 0) = src_reg;
00737 }
00738 else
00739 {
00740 rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);
00741 if (note)
00742 remove_note (p, note);
00743 }
00744 }
00745
00746
00747
00748
00749
00750 static void
00751 copy_src_to_dest (insn, src, dest, old_max_uid)
00752 rtx insn;
00753 rtx src;
00754 rtx dest;
00755 int old_max_uid;
00756 {
00757 rtx seq;
00758 rtx link;
00759 rtx next;
00760 rtx set;
00761 rtx move_insn;
00762 rtx *p_insn_notes;
00763 rtx *p_move_notes;
00764 int src_regno;
00765 int dest_regno;
00766 int bb;
00767 int insn_uid;
00768 int move_uid;
00769
00770
00771
00772
00773
00774
00775 if (GET_CODE (src) == REG
00776 && REG_LIVE_LENGTH (REGNO (src)) > 0
00777 && GET_CODE (dest) == REG
00778 && !RTX_UNCHANGING_P (dest)
00779 && REG_LIVE_LENGTH (REGNO (dest)) > 0
00780 && (set = single_set (insn)) != NULL_RTX
00781 && !reg_mentioned_p (dest, SET_SRC (set))
00782 && GET_MODE (src) == GET_MODE (dest))
00783 {
00784 int old_num_regs = reg_rtx_no;
00785
00786
00787 start_sequence ();
00788 emit_move_insn (dest, src);
00789 seq = get_insns ();
00790 end_sequence ();
00791
00792 if (old_num_regs != reg_rtx_no
00793 || ! validate_replace_rtx (src, dest, insn))
00794 {
00795
00796
00797
00798 reg_rtx_no = old_num_regs;
00799 return;
00800 }
00801 emit_insn_before (seq, insn);
00802 move_insn = PREV_INSN (insn);
00803 p_move_notes = ®_NOTES (move_insn);
00804 p_insn_notes = ®_NOTES (insn);
00805
00806
00807 for (link = REG_NOTES (insn); link != NULL_RTX; link = next)
00808 {
00809 next = XEXP (link, 1);
00810 if (XEXP (link, 0) == src)
00811 {
00812 *p_move_notes = link;
00813 p_move_notes = &XEXP (link, 1);
00814 }
00815 else
00816 {
00817 *p_insn_notes = link;
00818 p_insn_notes = &XEXP (link, 1);
00819 }
00820 }
00821
00822 *p_move_notes = NULL_RTX;
00823 *p_insn_notes = NULL_RTX;
00824
00825
00826 insn_uid = INSN_UID (insn);
00827 move_uid = INSN_UID (move_insn);
00828 if (insn_uid < old_max_uid)
00829 {
00830 bb = regmove_bb_head[insn_uid];
00831 if (bb >= 0)
00832 {
00833 BLOCK_HEAD (bb) = move_insn;
00834 regmove_bb_head[insn_uid] = -1;
00835 }
00836 }
00837
00838
00839 dest_regno = REGNO (dest);
00840 REG_N_SETS (dest_regno) ++;
00841 REG_LIVE_LENGTH (dest_regno)++;
00842 if (REGNO_FIRST_UID (dest_regno) == insn_uid)
00843 REGNO_FIRST_UID (dest_regno) = move_uid;
00844
00845 src_regno = REGNO (src);
00846 if (! find_reg_note (move_insn, REG_DEAD, src))
00847 REG_LIVE_LENGTH (src_regno)++;
00848
00849 if (REGNO_FIRST_UID (src_regno) == insn_uid)
00850 REGNO_FIRST_UID (src_regno) = move_uid;
00851
00852 if (REGNO_LAST_UID (src_regno) == insn_uid)
00853 REGNO_LAST_UID (src_regno) = move_uid;
00854
00855 if (REGNO_LAST_NOTE_UID (src_regno) == insn_uid)
00856 REGNO_LAST_NOTE_UID (src_regno) = move_uid;
00857 }
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 static int
00872 reg_is_remote_constant_p (reg, insn, first)
00873 rtx reg;
00874 rtx insn;
00875 rtx first;
00876 {
00877 rtx p;
00878
00879 if (REG_N_SETS (REGNO (reg)) != 1)
00880 return 0;
00881
00882
00883 for (p = LOG_LINKS (insn); p; p = XEXP (p, 1))
00884 {
00885 rtx s;
00886
00887 if (REG_NOTE_KIND (p) != 0)
00888 continue;
00889 s = single_set (XEXP (p, 0));
00890 if (s != 0
00891 && GET_CODE (SET_DEST (s)) == REG
00892 && REGNO (SET_DEST (s)) == REGNO (reg))
00893 {
00894
00895 return 0;
00896 }
00897 }
00898
00899 for (p = first; p && p != insn; p = NEXT_INSN (p))
00900 {
00901 rtx s;
00902
00903 if (! INSN_P (p))
00904 continue;
00905 s = single_set (p);
00906 if (s != 0
00907 && GET_CODE (SET_DEST (s)) == REG
00908 && REGNO (SET_DEST (s)) == REGNO (reg))
00909 {
00910
00911
00912 if (find_reg_note (p, REG_EQUAL, NULL_RTX))
00913 return 1;
00914 return 0;
00915 }
00916 }
00917
00918 return 0;
00919 }
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 static int
00940 fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
00941 rtx insn, dst, src, offset;
00942 FILE *regmove_dump_file;
00943 {
00944 rtx p, dst_death = 0;
00945 int length, num_calls = 0;
00946
00947
00948
00949
00950 if (find_regno_note (insn, REG_DEAD, REGNO (src)))
00951 return 0;
00952
00953
00954
00955 for (length = 0, p = PREV_INSN (insn); p; p = PREV_INSN (p))
00956 {
00957 rtx pset;
00958
00959
00960
00961 if (perhaps_ends_bb_p (p))
00962 break;
00963 else if (! INSN_P (p))
00964 continue;
00965
00966 if (find_regno_note (p, REG_DEAD, REGNO (dst)))
00967 dst_death = p;
00968 if (! dst_death)
00969 length++;
00970
00971 pset = single_set (p);
00972 if (pset && SET_DEST (pset) == dst
00973 && GET_CODE (SET_SRC (pset)) == PLUS
00974 && XEXP (SET_SRC (pset), 0) == src
00975 && GET_CODE (XEXP (SET_SRC (pset), 1)) == CONST_INT)
00976 {
00977 HOST_WIDE_INT newconst
00978 = INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
00979 rtx add = gen_add3_insn (dst, dst, GEN_INT (newconst));
00980
00981 if (add && validate_change (insn, &PATTERN (insn), add, 0))
00982 {
00983
00984 if (dst_death)
00985 {
00986 remove_death (REGNO (dst), dst_death);
00987 REG_LIVE_LENGTH (REGNO (dst)) += length;
00988 REG_N_CALLS_CROSSED (REGNO (dst)) += num_calls;
00989 }
00990
00991 if (regmove_dump_file)
00992 fprintf (regmove_dump_file,
00993 "Fixed operand of insn %d.\n",
00994 INSN_UID (insn));
00995
00996 #ifdef AUTO_INC_DEC
00997 for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
00998 {
00999 if (GET_CODE (p) == CODE_LABEL
01000 || GET_CODE (p) == JUMP_INSN)
01001 break;
01002 if (! INSN_P (p))
01003 continue;
01004 if (reg_overlap_mentioned_p (dst, PATTERN (p)))
01005 {
01006 if (try_auto_increment (p, insn, 0, dst, newconst, 0))
01007 return 1;
01008 break;
01009 }
01010 }
01011 for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
01012 {
01013 if (GET_CODE (p) == CODE_LABEL
01014 || GET_CODE (p) == JUMP_INSN)
01015 break;
01016 if (! INSN_P (p))
01017 continue;
01018 if (reg_overlap_mentioned_p (dst, PATTERN (p)))
01019 {
01020 try_auto_increment (p, insn, 0, dst, newconst, 1);
01021 break;
01022 }
01023 }
01024 #endif
01025 return 1;
01026 }
01027 }
01028
01029 if (reg_set_p (dst, PATTERN (p)))
01030 break;
01031
01032
01033
01034
01035
01036
01037
01038 if (GET_CODE (p) == CALL_INSN)
01039 {
01040 if (! dst_death)
01041 num_calls++;
01042
01043 if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
01044 break;
01045
01046 if (call_used_regs [REGNO (dst)]
01047 || find_reg_fusage (p, CLOBBER, dst))
01048 break;
01049 }
01050 else if (reg_set_p (src, PATTERN (p)))
01051 break;
01052 }
01053
01054 return 0;
01055 }
01056
01057
01058
01059
01060
01061
01062
01063 void
01064 regmove_optimize (f, nregs, regmove_dump_file)
01065 rtx f;
01066 int nregs;
01067 FILE *regmove_dump_file;
01068 {
01069 int old_max_uid = get_max_uid ();
01070 rtx insn;
01071 struct match match;
01072 int pass;
01073 int i;
01074 rtx copy_src, copy_dst;
01075 basic_block bb;
01076
01077
01078
01079 if (flag_non_call_exceptions)
01080 return;
01081
01082
01083
01084 mark_flags_life_zones (discover_flags_reg ());
01085
01086 regno_src_regno = (int *) xmalloc (sizeof *regno_src_regno * nregs);
01087 for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1;
01088
01089 regmove_bb_head = (int *) xmalloc (sizeof (int) * (old_max_uid + 1));
01090 for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1;
01091 FOR_EACH_BB (bb)
01092 regmove_bb_head[INSN_UID (bb->head)] = bb->index;
01093
01094
01095
01096 for (pass = 0; pass <= 2; pass++)
01097 {
01098 if (! flag_regmove && pass >= flag_expensive_optimizations)
01099 goto done;
01100
01101 if (regmove_dump_file)
01102 fprintf (regmove_dump_file, "Starting %s pass...\n",
01103 pass ? "backward" : "forward");
01104
01105 for (insn = pass ? get_last_insn () : f; insn;
01106 insn = pass ? PREV_INSN (insn) : NEXT_INSN (insn))
01107 {
01108 rtx set;
01109 int op_no, match_no;
01110
01111 set = single_set (insn);
01112 if (! set)
01113 continue;
01114
01115 if (flag_expensive_optimizations && ! pass
01116 && (GET_CODE (SET_SRC (set)) == SIGN_EXTEND
01117 || GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
01118 && GET_CODE (XEXP (SET_SRC (set), 0)) == REG
01119 && GET_CODE (SET_DEST (set)) == REG)
01120 optimize_reg_copy_3 (insn, SET_DEST (set), SET_SRC (set));
01121
01122 if (flag_expensive_optimizations && ! pass
01123 && GET_CODE (SET_SRC (set)) == REG
01124 && GET_CODE (SET_DEST (set)) == REG)
01125 {
01126
01127
01128
01129 if ((find_reg_note (insn, REG_DEAD, SET_SRC (set))
01130 || optimize_reg_copy_1 (insn, SET_DEST (set), SET_SRC (set)))
01131 && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
01132 {
01133
01134 if (REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
01135 optimize_reg_copy_2 (insn, SET_DEST (set), SET_SRC (set));
01136 if (regno_src_regno[REGNO (SET_DEST (set))] < 0
01137 && SET_SRC (set) != SET_DEST (set))
01138 {
01139 int srcregno = REGNO (SET_SRC (set));
01140 if (regno_src_regno[srcregno] >= 0)
01141 srcregno = regno_src_regno[srcregno];
01142 regno_src_regno[REGNO (SET_DEST (set))] = srcregno;
01143 }
01144 }
01145 }
01146 if (! flag_regmove)
01147 continue;
01148
01149 if (! find_matches (insn, &match))
01150 continue;
01151
01152
01153
01154
01155
01156
01157
01158
01159 for (op_no = 0; op_no < recog_data.n_operands; op_no++)
01160 {
01161 rtx src, dst, src_subreg;
01162 enum reg_class src_class, dst_class;
01163
01164 match_no = match.with[op_no];
01165
01166
01167 if (match_no < 0)
01168 continue;
01169
01170 src = recog_data.operand[op_no];
01171 dst = recog_data.operand[match_no];
01172
01173 if (GET_CODE (src) != REG)
01174 continue;
01175
01176 src_subreg = src;
01177 if (GET_CODE (dst) == SUBREG
01178 && GET_MODE_SIZE (GET_MODE (dst))
01179 >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst))))
01180 {
01181 src_subreg
01182 = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)),
01183 src, SUBREG_BYTE (dst));
01184 dst = SUBREG_REG (dst);
01185 }
01186 if (GET_CODE (dst) != REG
01187 || REGNO (dst) < FIRST_PSEUDO_REGISTER)
01188 continue;
01189
01190 if (REGNO (src) < FIRST_PSEUDO_REGISTER)
01191 {
01192 if (match.commutative[op_no] < op_no)
01193 regno_src_regno[REGNO (dst)] = REGNO (src);
01194 continue;
01195 }
01196
01197 if (REG_LIVE_LENGTH (REGNO (src)) < 0)
01198 continue;
01199
01200
01201
01202 if (match.use[op_no] != READ
01203 || match.use[match_no] != WRITE)
01204 continue;
01205
01206 if (match.early_clobber[match_no]
01207 && count_occurrences (PATTERN (insn), src, 0) > 1)
01208 continue;
01209
01210
01211 if (recog_data.operand[match_no] != SET_DEST (set))
01212 continue;
01213
01214
01215 if (operands_match_p (src, dst))
01216 continue;
01217
01218
01219 if (match.commutative[op_no] >= 0)
01220 {
01221 rtx comm = recog_data.operand[match.commutative[op_no]];
01222 if (operands_match_p (comm, dst)
01223 && (replacement_quality (comm)
01224 >= replacement_quality (src)))
01225 continue;
01226 }
01227
01228 src_class = reg_preferred_class (REGNO (src));
01229 dst_class = reg_preferred_class (REGNO (dst));
01230 if (! regclass_compatible_p (src_class, dst_class))
01231 continue;
01232
01233 if (GET_MODE (src) != GET_MODE (dst))
01234 continue;
01235
01236 if (fixup_match_1 (insn, set, src, src_subreg, dst, pass,
01237 op_no, match_no,
01238 regmove_dump_file))
01239 break;
01240 }
01241 }
01242 }
01243
01244
01245
01246 if (regmove_dump_file)
01247 fprintf (regmove_dump_file, "Starting backward pass...\n");
01248
01249 for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
01250 {
01251 if (INSN_P (insn))
01252 {
01253 int op_no, match_no;
01254 int success = 0;
01255
01256 if (! find_matches (insn, &match))
01257 continue;
01258
01259
01260
01261
01262
01263
01264
01265 copy_src = NULL_RTX;
01266 copy_dst = NULL_RTX;
01267 for (op_no = 0; op_no < recog_data.n_operands; op_no++)
01268 {
01269 rtx set, p, src, dst;
01270 rtx src_note, dst_note;
01271 int num_calls = 0;
01272 enum reg_class src_class, dst_class;
01273 int length;
01274
01275 match_no = match.with[op_no];
01276
01277
01278 if (match_no < 0)
01279 continue;
01280
01281 dst = recog_data.operand[match_no];
01282 src = recog_data.operand[op_no];
01283
01284 if (GET_CODE (src) != REG)
01285 continue;
01286
01287 if (GET_CODE (dst) != REG
01288 || REGNO (dst) < FIRST_PSEUDO_REGISTER
01289 || REG_LIVE_LENGTH (REGNO (dst)) < 0
01290 || RTX_UNCHANGING_P (dst))
01291 continue;
01292
01293
01294 if (operands_match_p (src, dst))
01295 continue;
01296
01297 if (match.commutative[op_no] >= 0)
01298 {
01299 rtx comm = recog_data.operand[match.commutative[op_no]];
01300 if (operands_match_p (comm, dst))
01301 continue;
01302 }
01303
01304 set = single_set (insn);
01305 if (! set)
01306 continue;
01307
01308
01309
01310
01311
01312
01313 if (reg_set_p (src, insn))
01314 continue;
01315
01316
01317
01318 if (match.use[op_no] != READ
01319 || match.use[match_no] != WRITE)
01320 continue;
01321
01322 if (match.early_clobber[match_no]
01323 && count_occurrences (PATTERN (insn), src, 0) > 1)
01324 continue;
01325
01326
01327 if (recog_data.operand[match_no] != SET_DEST (set))
01328 continue;
01329
01330 if (REGNO (src) < FIRST_PSEUDO_REGISTER)
01331 {
01332 if (GET_CODE (SET_SRC (set)) == PLUS
01333 && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
01334 && XEXP (SET_SRC (set), 0) == src
01335 && fixup_match_2 (insn, dst, src,
01336 XEXP (SET_SRC (set), 1),
01337 regmove_dump_file))
01338 break;
01339 continue;
01340 }
01341 src_class = reg_preferred_class (REGNO (src));
01342 dst_class = reg_preferred_class (REGNO (dst));
01343
01344 if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
01345 {
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355 continue;
01356 }
01357
01358 if (! regclass_compatible_p (src_class, dst_class))
01359 {
01360 if (!copy_src)
01361 {
01362 copy_src = src;
01363 copy_dst = dst;
01364 }
01365 continue;
01366 }
01367
01368
01369
01370 if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
01371 {
01372 if (!copy_src)
01373 {
01374 copy_src = src;
01375 copy_dst = dst;
01376 }
01377 continue;
01378 }
01379
01380
01381
01382
01383
01384
01385 if (reg_is_remote_constant_p (src, insn, f))
01386 {
01387 if (!copy_src)
01388 {
01389 copy_src = src;
01390 copy_dst = dst;
01391 }
01392 continue;
01393 }
01394
01395
01396 if (regmove_dump_file)
01397 fprintf (regmove_dump_file,
01398 "Could fix operand %d of insn %d matching operand %d.\n",
01399 op_no, INSN_UID (insn), match_no);
01400
01401
01402
01403
01404
01405 for (length = 0, p = PREV_INSN (insn); p; p = PREV_INSN (p))
01406 {
01407 rtx pset;
01408
01409
01410
01411
01412 if (perhaps_ends_bb_p (p))
01413 break;
01414 else if (! INSN_P (p))
01415 continue;
01416
01417 length++;
01418
01419
01420
01421 pset = single_set (p);
01422 if (pset && SET_DEST (pset) == src)
01423 {
01424
01425
01426
01427 if (validate_replace_rtx (src, dst, insn))
01428 {
01429 if (validate_change (p, &SET_DEST (pset),
01430 dst, 0))
01431 success = 1;
01432 else
01433 {
01434
01435
01436 validate_replace_rtx (dst, src, insn);
01437
01438 validate_change (insn,
01439 recog_data.operand_loc[match_no],
01440 dst, 0);
01441 }
01442 }
01443 break;
01444 }
01445
01446 if (reg_overlap_mentioned_p (src, PATTERN (p))
01447 || reg_overlap_mentioned_p (dst, PATTERN (p)))
01448 break;
01449
01450
01451
01452
01453 if (GET_CODE (p) == CALL_INSN)
01454 {
01455 num_calls++;
01456
01457 if (REG_N_CALLS_CROSSED (REGNO (dst)) == 0)
01458 break;
01459 }
01460 }
01461
01462 if (success)
01463 {
01464 int dstno, srcno;
01465
01466
01467 remove_note (insn, src_note);
01468
01469
01470 if (reg_overlap_mentioned_p (src, PATTERN (p)))
01471 {
01472 XEXP (src_note, 1) = REG_NOTES (p);
01473 REG_NOTES (p) = src_note;
01474 }
01475
01476
01477 if ((dst_note = find_reg_note (p, REG_DEAD, dst)))
01478 remove_note (p, dst_note);
01479
01480 dstno = REGNO (dst);
01481 srcno = REGNO (src);
01482
01483 REG_N_SETS (dstno)++;
01484 REG_N_SETS (srcno)--;
01485
01486 REG_N_CALLS_CROSSED (dstno) += num_calls;
01487 REG_N_CALLS_CROSSED (srcno) -= num_calls;
01488
01489 REG_LIVE_LENGTH (dstno) += length;
01490 if (REG_LIVE_LENGTH (srcno) >= 0)
01491 {
01492 REG_LIVE_LENGTH (srcno) -= length;
01493
01494
01495
01496 if (REG_LIVE_LENGTH (srcno) < 2)
01497 REG_LIVE_LENGTH (srcno) = 2;
01498 }
01499
01500 if (regmove_dump_file)
01501 fprintf (regmove_dump_file,
01502 "Fixed operand %d of insn %d matching operand %d.\n",
01503 op_no, INSN_UID (insn), match_no);
01504
01505 break;
01506 }
01507 }
01508
01509
01510
01511 if (!success && copy_src != NULL_RTX)
01512 copy_src_to_dest (insn, copy_src, copy_dst, old_max_uid);
01513
01514 }
01515 }
01516
01517
01518
01519 FOR_EACH_BB (bb)
01520 {
01521 rtx end = bb->end;
01522 rtx new = end;
01523 rtx next = NEXT_INSN (new);
01524 while (next != 0 && INSN_UID (next) >= old_max_uid
01525 && (bb->next_bb == EXIT_BLOCK_PTR || bb->next_bb->head != next))
01526 new = next, next = NEXT_INSN (new);
01527 bb->end = new;
01528 }
01529
01530 done:
01531
01532 free (regno_src_regno);
01533 free (regmove_bb_head);
01534 }
01535
01536
01537
01538
01539
01540
01541
01542 static int
01543 find_matches (insn, matchp)
01544 rtx insn;
01545 struct match *matchp;
01546 {
01547 int likely_spilled[MAX_RECOG_OPERANDS];
01548 int op_no;
01549 int any_matches = 0;
01550
01551 extract_insn (insn);
01552 if (! constrain_operands (0))
01553 return 0;
01554
01555
01556
01557
01558 for (op_no = recog_data.n_operands; --op_no >= 0; )
01559 matchp->with[op_no] = matchp->commutative[op_no] = -1;
01560
01561 for (op_no = 0; op_no < recog_data.n_operands; op_no++)
01562 {
01563 const char *p;
01564 char c;
01565 int i = 0;
01566
01567 p = recog_data.constraints[op_no];
01568
01569 likely_spilled[op_no] = 0;
01570 matchp->use[op_no] = READ;
01571 matchp->early_clobber[op_no] = 0;
01572 if (*p == '=')
01573 matchp->use[op_no] = WRITE;
01574 else if (*p == '+')
01575 matchp->use[op_no] = READWRITE;
01576
01577 for (;*p && i < which_alternative; p++)
01578 if (*p == ',')
01579 i++;
01580
01581 while ((c = *p++) != '\0' && c != ',')
01582 switch (c)
01583 {
01584 case '=':
01585 break;
01586 case '+':
01587 break;
01588 case '&':
01589 matchp->early_clobber[op_no] = 1;
01590 break;
01591 case '%':
01592 matchp->commutative[op_no] = op_no + 1;
01593 matchp->commutative[op_no + 1] = op_no;
01594 break;
01595
01596 case '0': case '1': case '2': case '3': case '4':
01597 case '5': case '6': case '7': case '8': case '9':
01598 {
01599 char *end;
01600 unsigned long match_ul = strtoul (p - 1, &end, 10);
01601 int match = match_ul;
01602
01603 p = end;
01604
01605 if (match < op_no && likely_spilled[match])
01606 break;
01607 matchp->with[op_no] = match;
01608 any_matches = 1;
01609 if (matchp->commutative[op_no] >= 0)
01610 matchp->with[matchp->commutative[op_no]] = match;
01611 }
01612 break;
01613
01614 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
01615 case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
01616 case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
01617 case 'C': case 'D': case 'W': case 'Y': case 'Z':
01618 if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_LETTER ((unsigned char) c)))
01619 likely_spilled[op_no] = 1;
01620 break;
01621 }
01622 }
01623 return any_matches;
01624 }
01625
01626
01627
01628
01629 static void
01630 replace_in_call_usage (loc, dst_reg, src, insn)
01631 rtx *loc;
01632 unsigned int dst_reg;
01633 rtx src;
01634 rtx insn;
01635 {
01636 rtx x = *loc;
01637 enum rtx_code code;
01638 const char *fmt;
01639 int i, j;
01640
01641 if (! x)
01642 return;
01643
01644 code = GET_CODE (x);
01645 if (code == REG)
01646 {
01647 if (REGNO (x) != dst_reg)
01648 return;
01649
01650 validate_change (insn, loc, src, 1);
01651
01652 return;
01653 }
01654
01655
01656 fmt = GET_RTX_FORMAT (code);
01657 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
01658 if (*fmt == 'e')
01659 replace_in_call_usage (&XEXP (x, i), dst_reg, src, insn);
01660 else if (*fmt == 'E')
01661 for (j = 0; j < XVECLEN (x, i); j++)
01662 replace_in_call_usage (& XVECEXP (x, i, j), dst_reg, src, insn);
01663 }
01664
01665
01666
01667
01668
01669
01670
01671
01672 static int
01673 fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
01674 match_number, regmove_dump_file)
01675 rtx insn, set, src, src_subreg, dst;
01676 int backward, operand_number, match_number;
01677 FILE *regmove_dump_file;
01678 {
01679 rtx p;
01680 rtx post_inc = 0, post_inc_set = 0, search_end = 0;
01681 int success = 0;
01682 int num_calls = 0, s_num_calls = 0;
01683 enum rtx_code code = NOTE;
01684 HOST_WIDE_INT insn_const = 0, newconst;
01685 rtx overlap = 0;
01686 rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note = NULL_RTX;
01687 int length, s_length;
01688
01689
01690
01691
01692 if (RTX_UNCHANGING_P (src))
01693 return 0;
01694
01695 if (! src_note)
01696 {
01697
01698
01699
01700
01701
01702
01703
01704
01705 code = GET_CODE (SET_SRC (set));
01706 if ((code == PLUS || code == LSHIFTRT
01707 || code == ASHIFT || code == ASHIFTRT)
01708 && XEXP (SET_SRC (set), 0) == src
01709 && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
01710 insn_const = INTVAL (XEXP (SET_SRC (set), 1));
01711 else if (! stable_and_no_regs_but_for_p (SET_SRC (set), src, dst))
01712 return 0;
01713 else
01714
01715 code = NOTE;
01716 }
01717
01718 if (regmove_dump_file)
01719 fprintf (regmove_dump_file,
01720 "Could fix operand %d of insn %d matching operand %d.\n",
01721 operand_number, INSN_UID (insn), match_number);
01722
01723
01724
01725
01726
01727 if (reg_is_remote_constant_p (src, insn, get_insns ()))
01728 return 0;
01729
01730
01731
01732
01733
01734
01735 for (length = s_length = 0, p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
01736 {
01737 if (GET_CODE (p) == CALL_INSN)
01738 replace_in_call_usage (& CALL_INSN_FUNCTION_USAGE (p),
01739 REGNO (dst), src, p);
01740
01741
01742
01743 if (perhaps_ends_bb_p (p))
01744 break;
01745 else if (! INSN_P (p))
01746 continue;
01747
01748 length++;
01749 if (src_note)
01750 s_length++;
01751
01752 if (reg_set_p (src, p) || reg_set_p (dst, p)
01753 || (GET_CODE (PATTERN (p)) == USE
01754 && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
01755 break;
01756
01757
01758
01759 if ((dst_note = find_regno_note (p, REG_DEAD, REGNO (dst)))
01760 && (GET_MODE (XEXP (dst_note, 0)) == GET_MODE (dst)))
01761 {
01762
01763
01764
01765
01766 if (overlap && GET_MODE (PREV_INSN (p)) != VOIDmode)
01767 break;
01768
01769 if (! src_note)
01770 {
01771 rtx q;
01772 rtx set2 = NULL_RTX;
01773
01774
01775
01776 if (reg_overlap_mentioned_p (src, PATTERN (p)))
01777 break;
01778 for (q = p; q; q = NEXT_INSN (q))
01779 {
01780
01781
01782
01783 if (perhaps_ends_bb_p (q))
01784 {
01785 q = 0;
01786 break;
01787 }
01788 else if (! INSN_P (q))
01789 continue;
01790 else if (reg_overlap_mentioned_p (src, PATTERN (q))
01791 || reg_set_p (src, q))
01792 break;
01793 }
01794 if (q)
01795 set2 = single_set (q);
01796 if (! q || ! set2 || GET_CODE (SET_SRC (set2)) != code
01797 || XEXP (SET_SRC (set2), 0) != src
01798 || GET_CODE (XEXP (SET_SRC (set2), 1)) != CONST_INT
01799 || (SET_DEST (set2) != src
01800 && ! find_reg_note (q, REG_DEAD, src)))
01801 {
01802
01803
01804
01805
01806
01807
01808 if (code == PLUS && backward
01809
01810
01811
01812 && ! (dst_note && ! REG_N_CALLS_CROSSED (REGNO (dst))
01813 && single_set (p)
01814 && GET_CODE (SET_DEST (single_set (p))) == REG
01815 && (REGNO (SET_DEST (single_set (p)))
01816 < FIRST_PSEUDO_REGISTER))
01817
01818
01819 && GET_MODE (p) == VOIDmode)
01820 {
01821 search_end = q;
01822 q = insn;
01823 set2 = set;
01824 newconst = -insn_const;
01825 code = MINUS;
01826 }
01827 else
01828 break;
01829 }
01830 else
01831 {
01832 newconst = INTVAL (XEXP (SET_SRC (set2), 1)) - insn_const;
01833
01834 if (code != PLUS
01835 && (newconst < 0
01836 || ((unsigned HOST_WIDE_INT) newconst
01837 >= (GET_MODE_BITSIZE (GET_MODE
01838 (SET_SRC (set2)))))))
01839 break;
01840 if (code == PLUS)
01841 {
01842 post_inc = q;
01843 if (SET_DEST (set2) != src)
01844 post_inc_set = set2;
01845 }
01846 }
01847
01848
01849
01850 validate_change (q, &XEXP (SET_SRC (set2), 1),
01851 GEN_INT (newconst), 1);
01852 }
01853 validate_change (insn, recog_data.operand_loc[match_number], src, 1);
01854 if (validate_replace_rtx (dst, src_subreg, p))
01855 success = 1;
01856 break;
01857 }
01858
01859 if (reg_overlap_mentioned_p (dst, PATTERN (p)))
01860 break;
01861 if (! src_note && reg_overlap_mentioned_p (src, PATTERN (p)))
01862 {
01863
01864
01865
01866
01867
01868 overlap = p;
01869 src_note = find_reg_note (p, REG_DEAD, src);
01870 }
01871
01872
01873
01874 if (GET_CODE (p) == CALL_INSN)
01875 {
01876 if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
01877 break;
01878
01879 num_calls++;
01880
01881 if (src_note)
01882 s_num_calls++;
01883
01884 }
01885 }
01886
01887 if (! success)
01888 return 0;
01889
01890
01891 remove_note (p, dst_note);
01892 if (code == MINUS)
01893 {
01894 post_inc = emit_insn_after (copy_rtx (PATTERN (insn)), p);
01895 if ((HAVE_PRE_INCREMENT || HAVE_PRE_DECREMENT)
01896 && search_end
01897 && try_auto_increment (search_end, post_inc, 0, src, newconst, 1))
01898 post_inc = 0;
01899 validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (insn_const), 0);
01900 REG_N_SETS (REGNO (src))++;
01901 REG_LIVE_LENGTH (REGNO (src))++;
01902 }
01903 if (overlap)
01904 {
01905
01906
01907 rtx pat = PATTERN (insn);
01908 if (src_note)
01909 remove_note (overlap, src_note);
01910 if ((HAVE_POST_INCREMENT || HAVE_POST_DECREMENT)
01911 && code == PLUS
01912 && try_auto_increment (overlap, insn, 0, src, insn_const, 0))
01913 insn = overlap;
01914 else
01915 {
01916 rtx notes = REG_NOTES (insn);
01917
01918 emit_insn_after_with_line_notes (pat, PREV_INSN (p), insn);
01919 delete_insn (insn);
01920
01921
01922 insn = p;
01923 while (! INSN_P (insn) || PATTERN (insn) != pat)
01924 insn = PREV_INSN (insn);
01925
01926 REG_NOTES (insn) = notes;
01927 }
01928 }
01929
01930
01931
01932
01933 if (! overlap && (code == PLUS || code == MINUS))
01934 {
01935 rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
01936 rtx q, set2 = NULL_RTX;
01937 int num_calls2 = 0, s_length2 = 0;
01938
01939 if (note && CONSTANT_P (XEXP (note, 0)))
01940 {
01941 for (q = PREV_INSN (insn); q; q = PREV_INSN (q))
01942 {
01943
01944
01945
01946 if (perhaps_ends_bb_p (q))
01947 {
01948 q = 0;
01949 break;
01950 }
01951 else if (! INSN_P (q))
01952 continue;
01953
01954 s_length2++;
01955 if (reg_set_p (src, q))
01956 {
01957 set2 = single_set (q);
01958 break;
01959 }
01960 if (reg_overlap_mentioned_p (src, PATTERN (q)))
01961 {
01962 q = 0;
01963 break;
01964 }
01965 if (GET_CODE (p) == CALL_INSN)
01966 num_calls2++;
01967 }
01968 if (q && set2 && SET_DEST (set2) == src && CONSTANT_P (SET_SRC (set2))
01969 && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
01970 {
01971 delete_insn (q);
01972 REG_N_SETS (REGNO (src))--;
01973 REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2;
01974 REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
01975 insn_const = 0;
01976 }
01977 }
01978 }
01979
01980 if ((HAVE_PRE_INCREMENT || HAVE_PRE_DECREMENT)
01981 && (code == PLUS || code == MINUS) && insn_const
01982 && try_auto_increment (p, insn, 0, src, insn_const, 1))
01983 insn = p;
01984 else if ((HAVE_POST_INCREMENT || HAVE_POST_DECREMENT)
01985 && post_inc
01986 && try_auto_increment (p, post_inc, post_inc_set, src, newconst, 0))
01987 post_inc = 0;
01988
01989
01990
01991 if (post_inc && code == PLUS
01992
01993
01994 && ((HAVE_PRE_INCREMENT && newconst > 0 && newconst <= MOVE_MAX)
01995 || (HAVE_PRE_DECREMENT && newconst < 0 && newconst >= -MOVE_MAX))
01996 && exact_log2 (newconst))
01997 {
01998 rtx q, inc_dest;
01999
02000 inc_dest = post_inc_set ? SET_DEST (post_inc_set) : src;
02001 for (q = post_inc; (q = NEXT_INSN (q)); )
02002 {
02003
02004
02005
02006 if (perhaps_ends_bb_p (q))
02007 break;
02008 else if (! INSN_P (q))
02009 continue;
02010 else if (src != inc_dest
02011 && (reg_overlap_mentioned_p (src, PATTERN (q))
02012 || reg_set_p (src, q)))
02013 break;
02014 else if (reg_set_p (inc_dest, q))
02015 break;
02016 else if (reg_overlap_mentioned_p (inc_dest, PATTERN (q)))
02017 {
02018 try_auto_increment (q, post_inc,
02019 post_inc_set, inc_dest, newconst, 1);
02020 break;
02021 }
02022 }
02023 }
02024
02025
02026
02027 if (reg_overlap_mentioned_p (dst, PATTERN (insn)))
02028 {
02029 XEXP (dst_note, 1) = REG_NOTES (insn);
02030 REG_NOTES (insn) = dst_note;
02031 }
02032
02033 if (src_note)
02034 {
02035
02036 if (! overlap)
02037 remove_note (insn, src_note);
02038 XEXP (src_note, 1) = REG_NOTES (p);
02039 REG_NOTES (p) = src_note;
02040
02041 REG_N_CALLS_CROSSED (REGNO (src)) += s_num_calls;
02042 }
02043
02044 REG_N_SETS (REGNO (src))++;
02045 REG_N_SETS (REGNO (dst))--;
02046
02047 REG_N_CALLS_CROSSED (REGNO (dst)) -= num_calls;
02048
02049 REG_LIVE_LENGTH (REGNO (src)) += s_length;
02050 if (REG_LIVE_LENGTH (REGNO (dst)) >= 0)
02051 {
02052 REG_LIVE_LENGTH (REGNO (dst)) -= length;
02053
02054
02055
02056 if (REG_LIVE_LENGTH (REGNO (dst)) < 2)
02057 REG_LIVE_LENGTH (REGNO (dst)) = 2;
02058 }
02059 if (regmove_dump_file)
02060 fprintf (regmove_dump_file,
02061 "Fixed operand %d of insn %d matching operand %d.\n",
02062 operand_number, INSN_UID (insn), match_number);
02063 return 1;
02064 }
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075 static int
02076 stable_and_no_regs_but_for_p (x, src, dst)
02077 rtx x, src, dst;
02078 {
02079 RTX_CODE code = GET_CODE (x);
02080 switch (GET_RTX_CLASS (code))
02081 {
02082 case '<': case '1': case 'c': case '2': case 'b': case '3':
02083 {
02084 int i;
02085 const char *fmt = GET_RTX_FORMAT (code);
02086 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
02087 if (fmt[i] == 'e'
02088 && ! stable_and_no_regs_but_for_p (XEXP (x, i), src, dst))
02089 return 0;
02090 return 1;
02091 }
02092 case 'o':
02093 if (code == REG)
02094 return x == src || x == dst;
02095
02096
02097 if (code == MEM
02098 && ! stable_and_no_regs_but_for_p (XEXP (x, 0), src, dst))
02099 return 0;
02100
02101 default:
02102 return ! rtx_unstable_p (x);
02103 }
02104 }
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130 struct csa_memlist
02131 {
02132 HOST_WIDE_INT sp_offset;
02133 rtx insn, *mem;
02134 struct csa_memlist *next;
02135 };
02136
02137 static int stack_memref_p PARAMS ((rtx));
02138 static rtx single_set_for_csa PARAMS ((rtx));
02139 static void free_csa_memlist PARAMS ((struct csa_memlist *));
02140 static struct csa_memlist *record_one_stack_memref
02141 PARAMS ((rtx, rtx *, struct csa_memlist *));
02142 static int try_apply_stack_adjustment
02143 PARAMS ((rtx, struct csa_memlist *, HOST_WIDE_INT, HOST_WIDE_INT));
02144 static void combine_stack_adjustments_for_block PARAMS ((basic_block));
02145 static int record_stack_memrefs PARAMS ((rtx *, void *));
02146
02147
02148
02149
02150 void
02151 combine_stack_adjustments ()
02152 {
02153 basic_block bb;
02154
02155 FOR_EACH_BB (bb)
02156 combine_stack_adjustments_for_block (bb);
02157 }
02158
02159
02160
02161 static int
02162 stack_memref_p (x)
02163 rtx x;
02164 {
02165 if (GET_CODE (x) != MEM)
02166 return 0;
02167 x = XEXP (x, 0);
02168
02169 if (x == stack_pointer_rtx)
02170 return 1;
02171 if (GET_CODE (x) == PLUS
02172 && XEXP (x, 0) == stack_pointer_rtx
02173 && GET_CODE (XEXP (x, 1)) == CONST_INT)
02174 return 1;
02175
02176 return 0;
02177 }
02178
02179
02180
02181
02182 static rtx
02183 single_set_for_csa (insn)
02184 rtx insn;
02185 {
02186 int i;
02187 rtx tmp = single_set (insn);
02188 if (tmp)
02189 return tmp;
02190
02191 if (GET_CODE (insn) != INSN
02192 || GET_CODE (PATTERN (insn)) != PARALLEL)
02193 return NULL_RTX;
02194
02195 tmp = PATTERN (insn);
02196 if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
02197 return NULL_RTX;
02198
02199 for (i = 1; i < XVECLEN (tmp, 0); ++i)
02200 {
02201 rtx this = XVECEXP (tmp, 0, i);
02202
02203
02204 if (GET_CODE (this) == SET
02205 && SET_SRC (this) == SET_DEST (this))
02206 ;
02207 else if (GET_CODE (this) != CLOBBER
02208 && GET_CODE (this) != USE)
02209 return NULL_RTX;
02210 }
02211
02212 return XVECEXP (tmp, 0, 0);
02213 }
02214
02215
02216
02217 static void
02218 free_csa_memlist (memlist)
02219 struct csa_memlist *memlist;
02220 {
02221 struct csa_memlist *next;
02222 for (; memlist ; memlist = next)
02223 {
02224 next = memlist->next;
02225 free (memlist);
02226 }
02227 }
02228
02229
02230
02231
02232 static struct csa_memlist *
02233 record_one_stack_memref (insn, mem, next_memlist)
02234 rtx insn, *mem;
02235 struct csa_memlist *next_memlist;
02236 {
02237 struct csa_memlist *ml;
02238
02239 ml = (struct csa_memlist *) xmalloc (sizeof (*ml));
02240
02241 if (XEXP (*mem, 0) == stack_pointer_rtx)
02242 ml->sp_offset = 0;
02243 else
02244 ml->sp_offset = INTVAL (XEXP (XEXP (*mem, 0), 1));
02245
02246 ml->insn = insn;
02247 ml->mem = mem;
02248 ml->next = next_memlist;
02249
02250 return ml;
02251 }
02252
02253
02254
02255
02256 static int
02257 try_apply_stack_adjustment (insn, memlist, new_adjust, delta)
02258 rtx insn;
02259 struct csa_memlist *memlist;
02260 HOST_WIDE_INT new_adjust, delta;
02261 {
02262 struct csa_memlist *ml;
02263 rtx set;
02264
02265 set = single_set_for_csa (insn);
02266 validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
02267
02268 for (ml = memlist; ml ; ml = ml->next)
02269 validate_change
02270 (ml->insn, ml->mem,
02271 replace_equiv_address_nv (*ml->mem,
02272 plus_constant (stack_pointer_rtx,
02273 ml->sp_offset - delta)), 1);
02274
02275 if (apply_change_group ())
02276 {
02277
02278 for (ml = memlist; ml ; ml = ml->next)
02279 ml->sp_offset -= delta;
02280
02281 return 1;
02282 }
02283 else
02284 return 0;
02285 }
02286
02287
02288
02289 struct record_stack_memrefs_data
02290 {
02291 rtx insn;
02292 struct csa_memlist *memlist;
02293 };
02294
02295 static int
02296 record_stack_memrefs (xp, data)
02297 rtx *xp;
02298 void *data;
02299 {
02300 rtx x = *xp;
02301 struct record_stack_memrefs_data *d =
02302 (struct record_stack_memrefs_data *) data;
02303 if (!x)
02304 return 0;
02305 switch (GET_CODE (x))
02306 {
02307 case MEM:
02308 if (!reg_mentioned_p (stack_pointer_rtx, x))
02309 return -1;
02310
02311
02312 if (stack_memref_p (x))
02313 {
02314 d->memlist = record_one_stack_memref (d->insn, xp, d->memlist);
02315 return -1;
02316 }
02317 return 1;
02318 case REG:
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328 if (REGNO (x) == STACK_POINTER_REGNUM)
02329 return 1;
02330 break;
02331 default:
02332 break;
02333 }
02334 return 0;
02335 }
02336
02337
02338
02339 static void
02340 combine_stack_adjustments_for_block (bb)
02341 basic_block bb;
02342 {
02343 HOST_WIDE_INT last_sp_adjust = 0;
02344 rtx last_sp_set = NULL_RTX;
02345 struct csa_memlist *memlist = NULL;
02346 rtx insn, next, set;
02347 struct record_stack_memrefs_data data;
02348 bool end_of_block = false;
02349
02350 for (insn = bb->head; !end_of_block ; insn = next)
02351 {
02352 end_of_block = insn == bb->end;
02353 next = NEXT_INSN (insn);
02354
02355 if (! INSN_P (insn))
02356 continue;
02357
02358 set = single_set_for_csa (insn);
02359 if (set)
02360 {
02361 rtx dest = SET_DEST (set);
02362 rtx src = SET_SRC (set);
02363
02364
02365 if (dest == stack_pointer_rtx
02366 && GET_CODE (src) == PLUS
02367 && XEXP (src, 0) == stack_pointer_rtx
02368 && GET_CODE (XEXP (src, 1)) == CONST_INT)
02369 {
02370 HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
02371
02372
02373
02374 if (! last_sp_set)
02375 {
02376 last_sp_set = insn;
02377 last_sp_adjust = this_adjust;
02378 continue;
02379 }
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402
02403 if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
02404 {
02405 if (try_apply_stack_adjustment (last_sp_set, memlist,
02406 last_sp_adjust + this_adjust,
02407 this_adjust))
02408 {
02409
02410 delete_insn (insn);
02411 last_sp_adjust += this_adjust;
02412 continue;
02413 }
02414 }
02415
02416
02417
02418 else if (STACK_GROWS_DOWNWARD
02419 ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
02420 {
02421 if (try_apply_stack_adjustment (insn, memlist,
02422 last_sp_adjust + this_adjust,
02423 -last_sp_adjust))
02424 {
02425
02426 delete_insn (last_sp_set);
02427 last_sp_set = insn;
02428 last_sp_adjust += this_adjust;
02429 free_csa_memlist (memlist);
02430 memlist = NULL;
02431 continue;
02432 }
02433 }
02434
02435
02436
02437
02438 if (last_sp_set && last_sp_adjust == 0)
02439 delete_insn (insn);
02440 free_csa_memlist (memlist);
02441 memlist = NULL;
02442 last_sp_set = insn;
02443 last_sp_adjust = this_adjust;
02444 continue;
02445 }
02446
02447
02448
02449
02450 if (memlist == NULL
02451 && GET_CODE (dest) == MEM
02452 && ((GET_CODE (XEXP (dest, 0)) == PRE_DEC
02453 && (last_sp_adjust
02454 == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
02455 || (GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
02456 && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
02457 && XEXP (XEXP (XEXP (dest, 0), 1), 0) == stack_pointer_rtx
02458 && (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
02459 == CONST_INT)
02460 && (INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
02461 == -last_sp_adjust)))
02462 && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
02463 && ! reg_mentioned_p (stack_pointer_rtx, src)
02464 && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
02465 && validate_change (insn, &SET_DEST (set),
02466 replace_equiv_address (dest,
02467 stack_pointer_rtx),
02468 0))
02469 {
02470 delete_insn (last_sp_set);
02471 free_csa_memlist (memlist);
02472 memlist = NULL;
02473 last_sp_set = NULL_RTX;
02474 last_sp_adjust = 0;
02475 continue;
02476 }
02477 }
02478
02479 data.insn = insn;
02480 data.memlist = memlist;
02481 if (GET_CODE (insn) != CALL_INSN && last_sp_set
02482 && !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data))
02483 {
02484 memlist = data.memlist;
02485 continue;
02486 }
02487 memlist = data.memlist;
02488
02489
02490
02491 if (last_sp_set
02492 && (GET_CODE (insn) == CALL_INSN
02493 || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
02494 {
02495 if (last_sp_set && last_sp_adjust == 0)
02496 delete_insn (last_sp_set);
02497 free_csa_memlist (memlist);
02498 memlist = NULL;
02499 last_sp_set = NULL_RTX;
02500 last_sp_adjust = 0;
02501 }
02502 }
02503
02504 if (last_sp_set && last_sp_adjust == 0)
02505 delete_insn (last_sp_set);
02506 }