From: amodra Date: Sun, 23 Aug 2009 02:57:26 +0000 (+0000) Subject: PR target/41081 X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=f92bd2dda8819e6c0128b58074e70bc72f0c927b;hp=71f666903a8de9f6f29cdbb85cfcca2d2de7ca8d PR target/41081 * fwprop.c (try_fwprop_subst): Allow multiple sets. (get_reg_use_in): New function. (forward_propagate_subreg): Propagate through subreg of zero_extend or sign_extend. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@151022 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3f690fac27b..cce751b2ed9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2009-08-23 Alan Modra + + PR target/41081 + * fwprop.c (try_fwprop_subst): Allow multiple sets. + (get_reg_use_in): New function. + (forward_propagate_subreg): Propagate through subreg of zero_extend + or sign_extend. + 2009-08-22 Kaz Kojima * config/sh/t-sh (TARGET_LIBGCC2_CFLAGS): Define. diff --git a/gcc/fwprop.c b/gcc/fwprop.c index df4edf93574..50daed2fc88 100644 --- a/gcc/fwprop.c +++ b/gcc/fwprop.c @@ -929,9 +929,14 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_ int flags = DF_REF_FLAGS (use); rtx set = single_set (insn); bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)); - int old_cost = rtx_cost (SET_SRC (set), SET, speed); + int old_cost = 0; bool ok; + /* forward_propagate_subreg may be operating on an instruction with + multiple sets. If so, assume the cost of the new instruction is + not greater than the old one. */ + if (set) + old_cost = rtx_cost (SET_SRC (set), SET, speed); if (dump_file) { fprintf (dump_file, "\nIn insn %d, replacing\n ", INSN_UID (insn)); @@ -951,6 +956,7 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_ } else if (DF_REF_TYPE (use) == DF_REF_REG_USE + && set && rtx_cost (SET_SRC (set), SET, speed) > old_cost) { if (dump_file) @@ -1008,8 +1014,26 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_ return ok; } +#ifdef LOAD_EXTEND_OP +static df_ref +get_reg_use_in (rtx insn, rtx reg) +{ + df_ref *use_vec; -/* If USE is a paradoxical subreg, see if it can be replaced by a pseudo. */ + for (use_vec = DF_INSN_USES (insn); *use_vec; use_vec++) + { + df_ref use = *use_vec; + + if (!DF_REF_IS_ARTIFICIAL (use) + && DF_REF_TYPE (use) == DF_REF_REG_USE + && DF_REF_REG (use) == reg) + return use; + } + return NULL; +} +#endif + +/* If USE is a subreg, see if it can be replaced by a pseudo. */ static bool forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set) @@ -1017,30 +1041,64 @@ forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set) rtx use_reg = DF_REF_REG (use); rtx use_insn, src; - /* Only consider paradoxical subregs... */ + /* Only consider subregs... */ enum machine_mode use_mode = GET_MODE (use_reg); if (GET_CODE (use_reg) != SUBREG - || !REG_P (SET_DEST (def_set)) - || GET_MODE_SIZE (use_mode) - <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg)))) + || !REG_P (SET_DEST (def_set))) return false; - /* If this is a paradoxical SUBREG, we have no idea what value the - extra bits would have. However, if the operand is equivalent to - a SUBREG whose operand is the same as our mode, and all the modes - are within a word, we can just use the inner operand because - these SUBREGs just say how to treat the register. */ - use_insn = DF_REF_INSN (use); - src = SET_SRC (def_set); - if (GET_CODE (src) == SUBREG - && REG_P (SUBREG_REG (src)) - && GET_MODE (SUBREG_REG (src)) == use_mode - && subreg_lowpart_p (src) - && all_uses_available_at (def_insn, use_insn)) - return try_fwprop_subst (use, DF_REF_LOC (use), SUBREG_REG (src), - def_insn, false); - else - return false; + /* If this is a paradoxical SUBREG... */ + if (GET_MODE_SIZE (use_mode) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg)))) + { + /* If this is a paradoxical SUBREG, we have no idea what value the + extra bits would have. However, if the operand is equivalent to + a SUBREG whose operand is the same as our mode, and all the modes + are within a word, we can just use the inner operand because + these SUBREGs just say how to treat the register. */ + use_insn = DF_REF_INSN (use); + src = SET_SRC (def_set); + if (GET_CODE (src) == SUBREG + && REG_P (SUBREG_REG (src)) + && GET_MODE (SUBREG_REG (src)) == use_mode + && subreg_lowpart_p (src) + && all_uses_available_at (def_insn, use_insn)) + return try_fwprop_subst (use, DF_REF_LOC (use), SUBREG_REG (src), + def_insn, false); + } + + /* If this is a SUBREG of a ZERO_EXTEND or SIGN_EXTEND, and the SUBREG + is the low part of the reg being extended then just use the inner + operand. Don't do this if the ZERO_EXTEND or SIGN_EXTEND insn will + be removed due to it matching a LOAD_EXTEND_OP load from memory. */ + else if (subreg_lowpart_p (use_reg)) + { +#ifdef LOAD_EXTEND_OP + df_ref prev_use, prev_def; +#endif + use_insn = DF_REF_INSN (use); + src = SET_SRC (def_set); + if ((GET_CODE (src) == ZERO_EXTEND + || GET_CODE (src) == SIGN_EXTEND) + && REG_P (XEXP (src, 0)) + && GET_MODE (XEXP (src, 0)) == use_mode +#ifdef LOAD_EXTEND_OP + && !(LOAD_EXTEND_OP (use_mode) == GET_CODE (src) + && (prev_use = get_reg_use_in (def_insn, XEXP (src, 0))) != NULL + && (prev_def = get_def_for_use (prev_use)) != NULL + && !DF_REF_IS_ARTIFICIAL (prev_def) + && NONJUMP_INSN_P (DF_REF_INSN (prev_def)) + && GET_CODE (PATTERN (DF_REF_INSN (prev_def))) == SET + && GET_CODE (SET_SRC (PATTERN (DF_REF_INSN (prev_def)))) == MEM + && rtx_equal_p (SET_DEST (PATTERN (DF_REF_INSN (prev_def))), + XEXP (src, 0))) +#endif + && all_uses_available_at (def_insn, use_insn)) + return try_fwprop_subst (use, DF_REF_LOC (use), XEXP (src, 0), + def_insn, false); + } + + return false; } /* Try to replace USE with SRC (defined in DEF_INSN) in __asm. */