X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fregmove.c;h=08cacf42bd188f34e03616637530d453e965f249;hp=f309f2163fbed5a0b34f13aecbcf63f6e9d21a5e;hb=f7229f1933eb32e2efe88e6dd6a3d40445d48038;hpb=8ad4c1110c5aca64439e92a7c1406f9d72397b69 diff --git a/gcc/regmove.c b/gcc/regmove.c index f309f2163fb..08cacf42bd1 100644 --- a/gcc/regmove.c +++ b/gcc/regmove.c @@ -1,6 +1,6 @@ /* Move registers around to reduce number of move instructions needed. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ /* This module looks for cases where matching constraints would force @@ -43,6 +43,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "except.h" #include "toplev.h" #include "reload.h" +#include "timevar.h" +#include "tree-pass.h" /* Turn STACK_GROWS_DOWNWARD into a boolean. */ @@ -135,7 +137,7 @@ try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg, /* If there is a REG_DEAD note on this insn, we must change this not to REG_UNUSED meaning that the register is set, but the value is dead. Failure to do so will - result in a sched1 abort -- when it recomputes lifetime + result in a sched1 dieing -- when it recomputes lifetime information, the number of REG_DEAD notes will have changed. */ rtx note = find_reg_note (insn, REG_DEAD, reg); @@ -266,7 +268,7 @@ mark_flags_life_zones (rtx flags) { int i; for (i = 0; i < flags_nregs; ++i) - live |= REGNO_REG_SET_P (block->global_live_at_start, + live |= REGNO_REG_SET_P (block->il.rtl->global_live_at_start, flags_regno + i); } #endif @@ -431,6 +433,9 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src) || (sregno < FIRST_PSEUDO_REGISTER && asm_noperands (PATTERN (p)) >= 0 && reg_overlap_mentioned_p (src, PATTERN (p))) + /* Don't change hard registers used by a call. */ + || (CALL_P (p) && sregno < FIRST_PSEUDO_REGISTER + && find_reg_fusage (p, USE, src)) /* Don't change a USE of a register. */ || (GET_CODE (PATTERN (p)) == USE && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0)))) @@ -491,7 +496,7 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src) /* If the insn in which SRC dies is a CALL_INSN, don't count it as a call that has been crossed. Otherwise, count it. */ - if (q != p && GET_CODE (q) == CALL_INSN) + if (q != p && CALL_P (q)) { /* Similarly, total calls for SREGNO, total calls beyond the death note for DREGNO. */ @@ -620,7 +625,7 @@ optimize_reg_copy_2 (rtx insn, rtx dest, rtx src) PATTERN (q) = replace_rtx (PATTERN (q), dest, src); - if (GET_CODE (q) == CALL_INSN) + if (CALL_P (q)) { REG_N_CALLS_CROSSED (dregno)--; REG_N_CALLS_CROSSED (sregno)++; @@ -636,7 +641,7 @@ optimize_reg_copy_2 (rtx insn, rtx dest, rtx src) if (reg_set_p (src, p) || find_reg_note (p, REG_DEAD, dest) - || (GET_CODE (p) == CALL_INSN && REG_N_CALLS_CROSSED (sregno) == 0)) + || (CALL_P (p) && REG_N_CALLS_CROSSED (sregno) == 0)) break; } } @@ -652,7 +657,7 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src) rtx src_reg = XEXP (src, 0); int src_no = REGNO (src_reg); int dst_no = REGNO (dest); - rtx p, set, subreg; + rtx p, set; enum machine_mode old_mode; if (src_no < FIRST_PSEUDO_REGISTER @@ -671,7 +676,7 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src) return; if (! (set = single_set (p)) - || GET_CODE (SET_SRC (set)) != MEM + || !MEM_P (SET_SRC (set)) /* If there's a REG_EQUIV note, this must be an insn that loads an argument. Prefer keeping the note over doing this optimization. */ || find_reg_note (p, REG_EQUIV, NULL_RTX) @@ -700,14 +705,15 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src) /* Now walk forward making additional replacements. We want to be able to undo all the changes if a later substitution fails. */ - subreg = gen_lowpart_SUBREG (old_mode, src_reg); while (p = NEXT_INSN (p), p != insn) { if (! INSN_P (p)) continue; /* Make a tentative change. */ - validate_replace_rtx_group (src_reg, subreg, p); + validate_replace_rtx_group (src_reg, + gen_lowpart_SUBREG (old_mode, src_reg), + p); } validate_replace_rtx_group (src, src_reg, insn); @@ -755,7 +761,6 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid) if (REG_P (src) && REG_LIVE_LENGTH (REGNO (src)) > 0 && REG_P (dest) - && !RTX_UNCHANGING_P (dest) && REG_LIVE_LENGTH (REGNO (dest)) > 0 && (set = single_set (insn)) != NULL_RTX && !reg_mentioned_p (dest, SET_SRC (set)) @@ -831,9 +836,6 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid) if (REGNO_LAST_UID (src_regno) == insn_uid) REGNO_LAST_UID (src_regno) = move_uid; - - if (REGNO_LAST_NOTE_UID (src_regno) == insn_uid) - REGNO_LAST_NOTE_UID (src_regno) = move_uid; } } @@ -971,8 +973,8 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file) #ifdef AUTO_INC_DEC for (p = PREV_INSN (insn); p; p = PREV_INSN (p)) { - if (GET_CODE (p) == CODE_LABEL - || GET_CODE (p) == JUMP_INSN) + if (LABEL_P (p) + || JUMP_P (p)) break; if (! INSN_P (p)) continue; @@ -985,8 +987,8 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file) } for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p)) { - if (GET_CODE (p) == CODE_LABEL - || GET_CODE (p) == JUMP_INSN) + if (LABEL_P (p) + || JUMP_P (p)) break; if (! INSN_P (p)) continue; @@ -1010,7 +1012,7 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file) /* reg_set_p is overly conservative for CALL_INSNS, thinks that all hard regs are clobbered. Thus, we only use it for src for non-call insns. */ - if (GET_CODE (p) == CALL_INSN) + if (CALL_P (p)) { if (! dst_death) num_calls++; @@ -1150,10 +1152,11 @@ regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file) && GET_MODE_SIZE (GET_MODE (dst)) >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst)))) { - src_subreg - = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)), - src, SUBREG_BYTE (dst)); dst = SUBREG_REG (dst); + src_subreg = lowpart_subreg (GET_MODE (dst), + src, GET_MODE (src)); + if (!src_subreg) + continue; } if (!REG_P (dst) || REGNO (dst) < FIRST_PSEUDO_REGISTER) @@ -1259,7 +1262,6 @@ regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file) if (!REG_P (dst) || REGNO (dst) < FIRST_PSEUDO_REGISTER || REG_LIVE_LENGTH (REGNO (dst)) < 0 - || RTX_UNCHANGING_P (dst) || GET_MODE (src) != GET_MODE (dst)) continue; @@ -1423,7 +1425,7 @@ regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file) /* If we have passed a call instruction, and the pseudo-reg DST is not already live across a call, then don't perform the optimization. */ - if (GET_CODE (p) == CALL_INSN) + if (CALL_P (p)) { num_calls++; @@ -1654,12 +1656,6 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note = NULL_RTX; int length, s_length; - /* If SRC is marked as unchanging, we may not change it. - ??? Maybe we could get better code by removing the unchanging bit - instead, and changing it back if we don't succeed? */ - if (RTX_UNCHANGING_P (src)) - return 0; - if (! src_note) { /* Look for (set (regX) (op regA constX)) @@ -1702,7 +1698,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, for (length = s_length = 0, p = NEXT_INSN (insn); p; p = NEXT_INSN (p)) { - if (GET_CODE (p) == CALL_INSN) + if (CALL_P (p)) replace_in_call_usage (& CALL_INSN_FUNCTION_USAGE (p), REGNO (dst), src, p); @@ -1839,7 +1835,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, /* If we have passed a call instruction, and the pseudo-reg SRC is not already live across a call, then don't perform the optimization. */ - if (GET_CODE (p) == CALL_INSN) + if (CALL_P (p)) { if (REG_N_CALLS_CROSSED (REGNO (src)) == 0) break; @@ -1930,7 +1926,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, q = 0; break; } - if (GET_CODE (p) == CALL_INSN) + if (CALL_P (p)) num_calls2++; } if (q && set2 && SET_DEST (set2) == src && CONSTANT_P (SET_SRC (set2)) @@ -2036,10 +2032,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, mentioning SRC or mentioning / changing DST . If in doubt, presume it is unstable. The rationale is that we want to check if we can move an insn easily - while just paying attention to SRC and DST. A register is considered - stable if it has the RTX_UNCHANGING_P bit set, but that would still - leave the burden to update REG_DEAD / REG_UNUSED notes, so we don't - want any registers but SRC and DST. */ + while just paying attention to SRC and DST. */ static int stable_and_no_regs_but_for_p (rtx x, rtx src, rtx dst) { @@ -2134,7 +2127,7 @@ combine_stack_adjustments (void) static int stack_memref_p (rtx x) { - if (GET_CODE (x) != MEM) + if (!MEM_P (x)) return 0; x = XEXP (x, 0); @@ -2159,7 +2152,7 @@ single_set_for_csa (rtx insn) if (tmp) return tmp; - if (GET_CODE (insn) != INSN + if (!NONJUMP_INSN_P (insn) || GET_CODE (PATTERN (insn)) != PARALLEL) return NULL_RTX; @@ -2411,7 +2404,7 @@ combine_stack_adjustments_for_block (basic_block bb) turn it into a direct store. Obviously we can't do this if there were any intervening uses of the stack pointer. */ if (memlist == NULL - && GET_CODE (dest) == MEM + && MEM_P (dest) && ((GET_CODE (XEXP (dest, 0)) == PRE_DEC && (last_sp_adjust == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))) @@ -2441,7 +2434,7 @@ combine_stack_adjustments_for_block (basic_block bb) data.insn = insn; data.memlist = memlist; - if (GET_CODE (insn) != CALL_INSN && last_sp_set + if (!CALL_P (insn) && last_sp_set && !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data)) { memlist = data.memlist; @@ -2452,7 +2445,7 @@ combine_stack_adjustments_for_block (basic_block bb) /* Otherwise, we were not able to process the instruction. Do not continue collecting data across such a one. */ if (last_sp_set - && (GET_CODE (insn) == CALL_INSN + && (CALL_P (insn) || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn)))) { if (last_sp_set && last_sp_adjust == 0) @@ -2466,4 +2459,84 @@ combine_stack_adjustments_for_block (basic_block bb) if (last_sp_set && last_sp_adjust == 0) delete_insn (last_sp_set); + + if (memlist) + free_csa_memlist (memlist); +} + +static bool +gate_handle_regmove (void) +{ + return (optimize > 0 && flag_regmove); } + + +/* Register allocation pre-pass, to reduce number of moves necessary + for two-address machines. */ +static void +rest_of_handle_regmove (void) +{ + regmove_optimize (get_insns (), max_reg_num (), dump_file); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); +} + +struct tree_opt_pass pass_regmove = +{ + "regmove", /* name */ + gate_handle_regmove, /* gate */ + rest_of_handle_regmove, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_REGMOVE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | + TODO_ggc_collect, /* todo_flags_finish */ + 'N' /* letter */ +}; + + +static bool +gate_handle_stack_adjustments (void) +{ + return (optimize > 0); +} + +static void +rest_of_handle_stack_adjustments (void) +{ + life_analysis (dump_file, PROP_POSTRELOAD); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE + | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)); + + /* This is kind of a heuristic. We need to run combine_stack_adjustments + even for machines with possibly nonzero RETURN_POPS_ARGS + and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having + push instructions will have popping returns. */ +#ifndef PUSH_ROUNDING + if (!ACCUMULATE_OUTGOING_ARGS) +#endif + combine_stack_adjustments (); +} + +struct tree_opt_pass pass_stack_adjustments = +{ + NULL, /* name */ + gate_handle_stack_adjustments, /* gate */ + rest_of_handle_stack_adjustments, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | + TODO_ggc_collect, /* todo_flags_finish */ + 0 /* letter */ +}; +