diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 37509933734..92be4a07fe4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2011-12-19 Richard Sandiford + + * fwprop.c (forward_propagate_subreg): Skip the SIGN/ZERO_EXTEND + optimization if the source register is already extended. + 2011-12-19 Richard Sandiford * lower-subreg.c (can_decompose_p): Check every word of a hard diff --git a/gcc/fwprop.c b/gcc/fwprop.c index 5368d187f4b..4fab5b06072 100644 --- a/gcc/fwprop.c +++ b/gcc/fwprop.c @@ -1112,7 +1112,18 @@ forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set) /* 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. */ + be removed due to it matching a LOAD_EXTEND_OP load from memory, + or due to the operation being a no-op when applied to registers. + For example, if we have: + + A: (set (reg:DI X) (sign_extend:DI (reg:SI Y))) + B: (... (subreg:SI (reg:DI X)) ...) + + and mode_rep_extended says that Y is already sign-extended, + the backend will typically allow A to be combined with the + definition of Y or, failing that, allow A to be deleted after + reload through register tying. Introducing more uses of Y + prevents both optimisations. */ else if (subreg_lowpart_p (use_reg)) { use_insn = DF_REF_INSN (use); @@ -1123,6 +1134,8 @@ forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set) && REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER && GET_MODE (XEXP (src, 0)) == use_mode && !free_load_extend (src, def_insn) + && (targetm.mode_rep_extended (use_mode, GET_MODE (src)) + != (int) GET_CODE (src)) && all_uses_available_at (def_insn, use_insn)) return try_fwprop_subst (use, DF_REF_LOC (use), XEXP (src, 0), def_insn, false);