X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fregmove.c;h=4cb083cbd48d7e935a5d8ab94c21eb848ceece7d;hb=2c03b0acbeff00d3cde74104382df749ea89a406;hp=d874695b9f44efaeae22a6861f3d93d9d9229c81;hpb=e1caca42389dcda67573909d11298755fbab833c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/regmove.c b/gcc/regmove.c index d874695b9f4..4cb083cbd48 100644 --- a/gcc/regmove.c +++ b/gcc/regmove.c @@ -1,12 +1,13 @@ /* 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, 2005 Free Software Foundation, Inc. + Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 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, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This module looks for cases where matching constraints would force @@ -45,22 +45,13 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "reload.h" #include "timevar.h" #include "tree-pass.h" - - -/* Turn STACK_GROWS_DOWNWARD into a boolean. */ -#ifdef STACK_GROWS_DOWNWARD -#undef STACK_GROWS_DOWNWARD -#define STACK_GROWS_DOWNWARD 1 -#else -#define STACK_GROWS_DOWNWARD 0 -#endif +#include "df.h" static int perhaps_ends_bb_p (rtx); static int optimize_reg_copy_1 (rtx, rtx, rtx); static void optimize_reg_copy_2 (rtx, rtx, rtx); static void optimize_reg_copy_3 (rtx, rtx, rtx); -static void copy_src_to_dest (rtx, rtx, rtx, int); -static int *regmove_bb_head; +static void copy_src_to_dest (rtx, rtx, rtx); struct match { int with[MAX_RECOG_OPERANDS]; @@ -71,7 +62,7 @@ struct match { static rtx discover_flags_reg (void); static void mark_flags_life_zones (rtx); -static void flags_set_1 (rtx, rtx, void *); +static void flags_set_1 (rtx, const_rtx, void *); static int try_auto_increment (rtx, rtx, rtx, rtx, HOST_WIDE_INT, int); static int find_matches (rtx, struct match *); @@ -94,6 +85,72 @@ regclass_compatible_p (int class0, int class1) && ! CLASS_LIKELY_SPILLED_P (class1))); } +/* Find the place in the rtx X where REG is used as a memory address. + Return the MEM rtx that so uses it. + If PLUSCONST is nonzero, search instead for a memory address equivalent to + (plus REG (const_int PLUSCONST)). + + If such an address does not appear, return 0. + If REG appears more than once, or is used other than in such an address, + return (rtx) 1. */ + +static rtx +find_use_as_address (rtx x, rtx reg, HOST_WIDE_INT plusconst) +{ + enum rtx_code code = GET_CODE (x); + const char * const fmt = GET_RTX_FORMAT (code); + int i; + rtx value = 0; + rtx tem; + + if (code == MEM && XEXP (x, 0) == reg && plusconst == 0) + return x; + + if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == reg + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) == plusconst) + return x; + + if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) + { + /* If REG occurs inside a MEM used in a bit-field reference, + that is unacceptable. */ + if (find_use_as_address (XEXP (x, 0), reg, 0) != 0) + return (rtx) (size_t) 1; + } + + if (x == reg) + return (rtx) (size_t) 1; + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + tem = find_use_as_address (XEXP (x, i), reg, plusconst); + if (value == 0) + value = tem; + else if (tem != 0) + return (rtx) (size_t) 1; + } + else if (fmt[i] == 'E') + { + int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + { + tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst); + if (value == 0) + value = tem; + else if (tem != 0) + return (rtx) (size_t) 1; + } + } + } + + return value; +} + + /* INC_INSN is an instruction that adds INCREMENT to REG. Try to fold INC_INSN as a post/pre in/decrement into INSN. Iff INC_INSN_SET is nonzero, inc_insn has a destination different from src. @@ -267,8 +324,7 @@ mark_flags_life_zones (rtx flags) { int i; for (i = 0; i < flags_nregs; ++i) - live |= REGNO_REG_SET_P (block->il.rtl->global_live_at_start, - flags_regno + i); + live |= REGNO_REG_SET_P (df_get_live_in (block), flags_regno + i); } #endif @@ -315,7 +371,7 @@ mark_flags_life_zones (rtx flags) /* A subroutine of mark_flags_life_zones, called through note_stores. */ static void -flags_set_1 (rtx x, rtx pat, void *data ATTRIBUTE_UNUSED) +flags_set_1 (rtx x, const_rtx pat, void *data ATTRIBUTE_UNUSED) { if (GET_CODE (pat) == SET && reg_overlap_mentioned_p (x, flags_set_1_rtx)) @@ -621,7 +677,10 @@ optimize_reg_copy_2 (rtx insn, rtx dest, rtx src) if (INSN_P (q)) { if (reg_mentioned_p (dest, PATTERN (q))) - PATTERN (q) = replace_rtx (PATTERN (q), dest, src); + { + PATTERN (q) = replace_rtx (PATTERN (q), dest, src); + df_insn_rescan (q); + } if (CALL_P (q)) { @@ -737,7 +796,7 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src) instead moving the value to dest directly before the operation. */ static void -copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid) +copy_src_to_dest (rtx insn, rtx src, rtx dest) { rtx seq; rtx link; @@ -748,7 +807,6 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid) rtx *p_move_notes; int src_regno; int dest_regno; - int bb; int insn_uid; int move_uid; @@ -806,35 +864,16 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid) *p_move_notes = NULL_RTX; *p_insn_notes = NULL_RTX; - /* Is the insn the head of a basic block? If so extend it. */ insn_uid = INSN_UID (insn); move_uid = INSN_UID (move_insn); - if (insn_uid < old_max_uid) - { - bb = regmove_bb_head[insn_uid]; - if (bb >= 0) - { - BB_HEAD (BASIC_BLOCK (bb)) = move_insn; - regmove_bb_head[insn_uid] = -1; - } - } /* Update the various register tables. */ dest_regno = REGNO (dest); - REG_N_SETS (dest_regno) ++; + INC_REG_N_SETS (dest_regno, 1); REG_LIVE_LENGTH (dest_regno)++; - if (REGNO_FIRST_UID (dest_regno) == insn_uid) - REGNO_FIRST_UID (dest_regno) = move_uid; - src_regno = REGNO (src); if (! find_reg_note (move_insn, REG_DEAD, src)) REG_LIVE_LENGTH (src_regno)++; - - if (REGNO_FIRST_UID (src_regno) == insn_uid) - REGNO_FIRST_UID (src_regno) = move_uid; - - if (REGNO_LAST_UID (src_regno) == insn_uid) - REGNO_LAST_UID (src_regno) = move_uid; } } @@ -854,8 +893,7 @@ static unsigned int max_reg_computed; may increase register pressure and make reload harder. If REG is set in the same basic block as INSN, we don't worry about it, because we'll probably need a register anyhow (??? but what if REG - is used in a different basic block as well as this one?). FIRST is - the first insn in the function. */ + is used in a different basic block as well as this one?). */ static bool reg_is_remote_constant_p (rtx reg, rtx insn) @@ -870,44 +908,27 @@ reg_is_remote_constant_p (rtx reg, rtx insn) reg_set_in_bb = xcalloc (max, sizeof (*reg_set_in_bb)); FOR_EACH_BB (bb) - for (p = BB_HEAD (bb); p != NEXT_INSN (BB_END (bb)); - p = NEXT_INSN (p)) - { - rtx s; - - if (!INSN_P (p)) - continue; - s = single_set (p); - /* This is the instruction which sets REG. If there is a - REG_EQUAL note, then REG is equivalent to a constant. */ - if (s != 0 - && REG_P (SET_DEST (s)) - && REG_N_SETS (REGNO (SET_DEST (s))) == 1 - && find_reg_note (p, REG_EQUAL, NULL_RTX)) - reg_set_in_bb[REGNO (SET_DEST (s))] = bb; - } + FOR_BB_INSNS (bb, p) + { + rtx s; + + if (!INSN_P (p)) + continue; + s = single_set (p); + /* This is the instruction which sets REG. If there is a + REG_EQUAL note, then REG is equivalent to a constant. */ + if (s != 0 + && REG_P (SET_DEST (s)) + && REG_N_SETS (REGNO (SET_DEST (s))) == 1 + && find_reg_note (p, REG_EQUAL, NULL_RTX)) + reg_set_in_bb[REGNO (SET_DEST (s))] = bb; + } } + gcc_assert (REGNO (reg) < max_reg_computed); if (reg_set_in_bb[REGNO (reg)] == NULL) return false; - if (reg_set_in_bb[REGNO (reg)] != BLOCK_FOR_INSN (insn)) - return true; - /* Look for the set. */ - for (p = BB_HEAD (BLOCK_FOR_INSN (insn)); p != insn; p = NEXT_INSN (p)) - { - rtx s; - - if (!INSN_P (p)) - continue; - s = single_set (p); - if (s != 0 - && REG_P (SET_DEST (s)) && REGNO (SET_DEST (s)) == REGNO (reg)) - { - /* The register is set in the same basic block. */ - return false; - } - } - return true; + return (reg_set_in_bb[REGNO (reg)] != BLOCK_FOR_INSN (insn)); } /* INSN is adding a CONST_INT to a REG. We search backwards looking for @@ -1053,30 +1074,30 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset) static void regmove_optimize (rtx f, int nregs) { - int old_max_uid = get_max_uid (); rtx insn; struct match match; int pass; int i; rtx copy_src, copy_dst; - basic_block bb; /* ??? Hack. Regmove doesn't examine the CFG, and gets mightily confused by non-call exceptions ending blocks. */ if (flag_non_call_exceptions) return; + df_note_add_problem (); + df_analyze (); + + regstat_init_n_sets_and_refs (); + regstat_compute_ri (); + /* Find out where a potential flags register is live, and so that we can suppress some optimizations in those zones. */ mark_flags_life_zones (discover_flags_reg ()); regno_src_regno = XNEWVEC (int, nregs); - for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1; - - regmove_bb_head = XNEWVEC (int, old_max_uid + 1); - for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1; - FOR_EACH_BB (bb) - regmove_bb_head[INSN_UID (BB_HEAD (bb))] = bb->index; + for (i = nregs; --i >= 0; ) + regno_src_regno[i] = -1; /* A forward/backward pass. Replace output operands with input operands. */ @@ -1471,8 +1492,8 @@ regmove_optimize (rtx f, int nregs) dstno = REGNO (dst); srcno = REGNO (src); - REG_N_SETS (dstno)++; - REG_N_SETS (srcno)--; + INC_REG_N_SETS (dstno, 1); + INC_REG_N_SETS (srcno, -1); REG_N_CALLS_CROSSED (dstno) += num_calls; REG_N_CALLS_CROSSED (srcno) -= num_calls; @@ -1500,33 +1521,20 @@ regmove_optimize (rtx f, int nregs) /* If we weren't able to replace any of the alternatives, try an alternative approach of copying the source to the destination. */ if (!success && copy_src != NULL_RTX) - copy_src_to_dest (insn, copy_src, copy_dst, old_max_uid); - + copy_src_to_dest (insn, copy_src, copy_dst); } } - /* In fixup_match_1, some insns may have been inserted after basic block - ends. Fix that here. */ - FOR_EACH_BB (bb) - { - rtx end = BB_END (bb); - rtx new = end; - rtx next = NEXT_INSN (new); - while (next != 0 && INSN_UID (next) >= old_max_uid - && (bb->next_bb == EXIT_BLOCK_PTR || BB_HEAD (bb->next_bb) != next)) - new = next, next = NEXT_INSN (new); - BB_END (bb) = new; - } - done: /* Clean up. */ free (regno_src_regno); - free (regmove_bb_head); if (reg_set_in_bb) { free (reg_set_in_bb); reg_set_in_bb = NULL; } + regstat_free_n_sets_and_refs (); + regstat_free_ri (); } /* Returns nonzero if INSN's pattern has matching constraints for any operand. @@ -1881,7 +1889,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, && try_auto_increment (search_end, post_inc, 0, src, newconst, 1)) post_inc = 0; validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (insn_const), 0); - REG_N_SETS (REGNO (src))++; + INC_REG_N_SETS (REGNO (src), 1); REG_LIVE_LENGTH (REGNO (src))++; } if (overlap) @@ -1902,6 +1910,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, p = emit_insn_after_setloc (pat, PREV_INSN (p), INSN_LOCATOR (insn)); delete_insn (insn); REG_NOTES (p) = notes; + df_notes_rescan (p); } } /* Sometimes we'd generate src = const; src += n; @@ -1947,7 +1956,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0)) { delete_insn (q); - REG_N_SETS (REGNO (src))--; + INC_REG_N_SETS (REGNO (src), -1); REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2; REG_LIVE_LENGTH (REGNO (src)) -= s_length2; insn_const = 0; @@ -2019,8 +2028,8 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, REG_N_CALLS_CROSSED (REGNO (src)) += s_num_calls; } - REG_N_SETS (REGNO (src))++; - REG_N_SETS (REGNO (dst))--; + INC_REG_N_SETS (REGNO (src), 1); + INC_REG_N_SETS (REGNO (dst), -1); REG_N_CALLS_CROSSED (REGNO (dst)) -= num_calls; @@ -2096,7 +2105,6 @@ static unsigned int rest_of_handle_regmove (void) { regmove_optimize (get_insns (), max_reg_num ()); - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); return 0; } @@ -2113,6 +2121,7 @@ struct tree_opt_pass pass_regmove = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ + TODO_df_finish | TODO_verify_rtl_sharing | TODO_dump_func | TODO_ggc_collect, /* todo_flags_finish */ 'N' /* letter */