OSDN Git Service

PR target/41081
authoramodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 23 Aug 2009 02:57:26 +0000 (02:57 +0000)
committeramodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 23 Aug 2009 02:57:26 +0000 (02:57 +0000)
* 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

gcc/ChangeLog
gcc/fwprop.c

index 3f690fa..cce751b 100644 (file)
@@ -1,3 +1,11 @@
+2009-08-23  Alan Modra  <amodra@bigpond.net.au>
+
+       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  <kkojima@gcc.gnu.org>
 
        * config/sh/t-sh (TARGET_LIBGCC2_CFLAGS): Define.
index df4edf9..50daed2 100644 (file)
@@ -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.  */