OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / fwprop.c
index 7f29ffb..4fab5b0 100644 (file)
@@ -1,5 +1,5 @@
 /* RTL-based forward propagation pass for GNU compiler.
-   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Paolo Bonzini and Steven Bosscher.
 
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 
 #include "sparseset.h"
 #include "timevar.h"
@@ -410,11 +409,11 @@ should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode,
          - address_cost (new_rtx, mode, as, speed));
 
   /* If the addresses have equivalent cost, prefer the new address
-     if it has the highest `rtx_cost'.  That has the potential of
+     if it has the highest `set_src_cost'.  That has the potential of
      eliminating the most insns without additional costs, and it
      is the same that cse.c used to do.  */
   if (gain == 0)
-    gain = rtx_cost (new_rtx, SET, speed) - rtx_cost (old_rtx, SET, speed);
+    gain = set_src_cost (new_rtx, speed) - set_src_cost (old_rtx, speed);
 
   return (gain > 0);
 }
@@ -964,7 +963,7 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_
      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);
+    old_cost = set_src_cost (SET_SRC (set), speed);
   if (dump_file)
     {
       fprintf (dump_file, "\nIn insn %d, replacing\n ", INSN_UID (insn));
@@ -985,7 +984,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)
+          && set_src_cost (SET_SRC (set), speed) > old_cost)
     {
       if (dump_file)
        fprintf (dump_file, "Changes to insn %d not profitable\n",
@@ -1102,6 +1101,7 @@ forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set)
       src = SET_SRC (def_set);
       if (GET_CODE (src) == SUBREG
          && REG_P (SUBREG_REG (src))
+         && REGNO (SUBREG_REG (src)) >= FIRST_PSEUDO_REGISTER
          && GET_MODE (SUBREG_REG (src)) == use_mode
          && subreg_lowpart_p (src)
          && all_uses_available_at (def_insn, use_insn))
@@ -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);
@@ -1120,8 +1131,11 @@ forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set)
       if ((GET_CODE (src) == ZERO_EXTEND
           || GET_CODE (src) == SIGN_EXTEND)
          && REG_P (XEXP (src, 0))
+         && 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);
@@ -1231,21 +1245,24 @@ forward_propagate_and_simplify (df_ref use, rtx def_insn, rtx def_set)
 
   /* If def and use are subreg, check if they match.  */
   reg = DF_REF_REG (use);
-  if (GET_CODE (reg) == SUBREG
-      && GET_CODE (SET_DEST (def_set)) == SUBREG
-      && (SUBREG_BYTE (SET_DEST (def_set)) != SUBREG_BYTE (reg)
-         || GET_MODE (SET_DEST (def_set)) != GET_MODE (reg)))
-    return false;
-
+  if (GET_CODE (reg) == SUBREG && GET_CODE (SET_DEST (def_set)) == SUBREG)
+    {
+      if (SUBREG_BYTE (SET_DEST (def_set)) != SUBREG_BYTE (reg))
+       return false;
+    }
   /* Check if the def had a subreg, but the use has the whole reg.  */
-  if (REG_P (reg) && GET_CODE (SET_DEST (def_set)) == SUBREG)
+  else if (REG_P (reg) && GET_CODE (SET_DEST (def_set)) == SUBREG)
     return false;
-
   /* Check if the use has a subreg, but the def had the whole reg.  Unlike the
      previous case, the optimization is possible and often useful indeed.  */
-  if (GET_CODE (reg) == SUBREG && REG_P (SET_DEST (def_set)))
+  else if (GET_CODE (reg) == SUBREG && REG_P (SET_DEST (def_set)))
     reg = SUBREG_REG (reg);
 
+  /* Make sure that we can treat REG as having the same mode as the
+     source of DEF_SET.  */
+  if (GET_MODE (SET_DEST (def_set)) != GET_MODE (reg))
+    return false;
+
   /* Check if the substitution is valid (last, because it's the most
      expensive check!).  */
   src = SET_SRC (def_set);
@@ -1316,9 +1333,10 @@ forward_propagate_and_simplify (df_ref use, rtx def_insn, rtx def_set)
 
 
 /* Given a use USE of an insn, if it has a single reaching
-   definition, try to forward propagate it into that insn.  */
+   definition, try to forward propagate it into that insn.
+   Return true if cfg cleanup will be needed.  */
 
-static void
+static bool
 forward_propagate_into (df_ref use)
 {
   df_ref def;
@@ -1326,22 +1344,22 @@ forward_propagate_into (df_ref use)
   rtx parent;
 
   if (DF_REF_FLAGS (use) & DF_REF_READ_WRITE)
-    return;
+    return false;
   if (DF_REF_IS_ARTIFICIAL (use))
-    return;
+    return false;
 
   /* Only consider uses that have a single definition.  */
   def = get_def_for_use (use);
   if (!def)
-    return;
+    return false;
   if (DF_REF_FLAGS (def) & DF_REF_READ_WRITE)
-    return;
+    return false;
   if (DF_REF_IS_ARTIFICIAL (def))
-    return;
+    return false;
 
   /* Do not propagate loop invariant definitions inside the loop.  */
   if (DF_REF_BB (def)->loop_father != DF_REF_BB (use)->loop_father)
-    return;
+    return false;
 
   /* Check if the use is still present in the insn!  */
   use_insn = DF_REF_INSN (use);
@@ -1351,19 +1369,26 @@ forward_propagate_into (df_ref use)
     parent = PATTERN (use_insn);
 
   if (!reg_mentioned_p (DF_REF_REG (use), parent))
-    return;
+    return false;
 
   def_insn = DF_REF_INSN (def);
   if (multiple_sets (def_insn))
-    return;
+    return false;
   def_set = single_set (def_insn);
   if (!def_set)
-    return;
+    return false;
 
   /* Only try one kind of propagation.  If two are possible, we'll
      do it on the following iterations.  */
-  if (!forward_propagate_and_simplify (use, def_insn, def_set))
-    forward_propagate_subreg (use, def_insn, def_set);
+  if (forward_propagate_and_simplify (use, def_insn, def_set)
+      || forward_propagate_subreg (use, def_insn, def_set))
+    {
+      if (cfun->can_throw_non_call_exceptions
+         && find_reg_note (use_insn, REG_EH_REGION, NULL_RTX)
+         && purge_dead_edges (DF_REF_BB (use)))
+       return true;
+    }
+  return false;
 }
 
 \f
@@ -1422,6 +1447,7 @@ static unsigned int
 fwprop (void)
 {
   unsigned i;
+  bool need_cleanup = false;
 
   fwprop_init ();
 
@@ -1439,10 +1465,12 @@ fwprop (void)
            || DF_REF_BB (use)->loop_father == NULL
            /* The outer most loop is not really a loop.  */
            || loop_outer (DF_REF_BB (use)->loop_father) == NULL)
-         forward_propagate_into (use);
+         need_cleanup |= forward_propagate_into (use);
     }
 
   fwprop_done ();
+  if (need_cleanup)
+    cleanup_cfg (0);
   return 0;
 }
 
@@ -1461,8 +1489,9 @@ struct rtl_opt_pass pass_rtl_fwprop =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_dump_func                        /* todo_flags_finish */
+  TODO_df_finish
+    | TODO_verify_flow
+    | TODO_verify_rtl_sharing           /* todo_flags_finish */
  }
 };
 
@@ -1470,6 +1499,8 @@ static unsigned int
 fwprop_addr (void)
 {
   unsigned i;
+  bool need_cleanup = false;
+
   fwprop_init ();
 
   /* Go through all the uses.  df_uses_create will create new ones at the
@@ -1482,11 +1513,13 @@ fwprop_addr (void)
            && DF_REF_BB (use)->loop_father != NULL
            /* The outer most loop is not really a loop.  */
            && loop_outer (DF_REF_BB (use)->loop_father) != NULL)
-         forward_propagate_into (use);
+         need_cleanup |= forward_propagate_into (use);
     }
 
   fwprop_done ();
 
+  if (need_cleanup)
+    cleanup_cfg (0);
   return 0;
 }
 
@@ -1505,7 +1538,6 @@ struct rtl_opt_pass pass_rtl_fwprop_addr =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_dump_func                        /* todo_flags_finish */
+  TODO_df_finish | TODO_verify_rtl_sharing  /* todo_flags_finish */
  }
 };