OSDN Git Service

PR target/23552
[pf3gnuchains/gcc-fork.git] / gcc / postreload.c
index 1213509..d164ae1 100644 (file)
@@ -1,6 +1,6 @@
 /* Perform simple optimizations to clean up the result of reload.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ 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, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -44,6 +44,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "except.h"
 #include "tree.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 static int reload_cse_noop_set_p (rtx);
 static void reload_cse_simplify (rtx, rtx);
@@ -118,6 +120,19 @@ reload_cse_simplify (rtx insn, rtx testreg)
       int count = 0;
       rtx value = NULL_RTX;
 
+      /* Registers mentioned in the clobber list for an asm cannot be reused
+        within the body of the asm.  Invalidate those registers now so that
+        we don't try to substitute values for them.  */
+      if (asm_noperands (body) >= 0)
+       {
+         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+           {
+             rtx part = XVECEXP (body, 0, i);
+             if (GET_CODE (part) == CLOBBER && REG_P (XEXP (part, 0)))
+               cselib_invalidate_rtx (XEXP (part, 0));
+           }
+       }
+
       /* If every action in a PARALLEL is a noop, we can delete
         the entire PARALLEL.  */
       for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
@@ -214,7 +229,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
   cselib_val *val;
   struct elt_loc_list *l;
 #ifdef LOAD_EXTEND_OP
-  enum rtx_code extend_op = NIL;
+  enum rtx_code extend_op = UNKNOWN;
 #endif
 
   dreg = true_regnum (SET_DEST (set));
@@ -234,7 +249,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
      the destination must be a register that we can widen.  */
   if (MEM_P (src)
       && GET_MODE_BITSIZE (GET_MODE (src)) < BITS_PER_WORD
-      && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != NIL
+      && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != UNKNOWN
       && !REG_P (SET_DEST (set)))
     return 0;
 #endif
@@ -260,7 +275,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
       if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
        {
 #ifdef LOAD_EXTEND_OP
-         if (extend_op != NIL)
+         if (extend_op != UNKNOWN)
            {
              HOST_WIDE_INT this_val;
 
@@ -280,7 +295,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
                  if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
                    break;
                default:
-                 abort ();
+                 gcc_unreachable ();
                }
              this_rtx = GEN_INT (this_val);
            }
@@ -290,7 +305,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
       else if (REG_P (this_rtx))
        {
 #ifdef LOAD_EXTEND_OP
-         if (extend_op != NIL)
+         if (extend_op != UNKNOWN)
            {
              this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
              this_cost = rtx_cost (this_rtx, SET);
@@ -313,7 +328,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
        {
 #ifdef LOAD_EXTEND_OP
          if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
-             && extend_op != NIL
+             && extend_op != UNKNOWN
 #ifdef CANNOT_CHANGE_MODE_CLASS
              && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
                                            word_mode,
@@ -396,7 +411,7 @@ reload_cse_simplify_operands (rtx insn, rtx testreg)
       /* cselib blows up on CODE_LABELs.  Trying to fix that doesn't seem
         right, so avoid the problem here.  Likewise if we have a constant
          and the insn pattern doesn't tell us the mode we need.  */
-      if (GET_CODE (recog_data.operand[i]) == CODE_LABEL
+      if (LABEL_P (recog_data.operand[i])
          || (CONSTANT_P (recog_data.operand[i])
              && recog_data.operand_mode[i] == VOIDmode))
        continue;
@@ -406,7 +421,7 @@ reload_cse_simplify_operands (rtx insn, rtx testreg)
 #ifdef LOAD_EXTEND_OP
       if (MEM_P (op)
          && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
-         && LOAD_EXTEND_OP (mode) != NIL)
+         && LOAD_EXTEND_OP (mode) != UNKNOWN)
        {
          rtx set = single_set (insn);
 
@@ -414,7 +429,7 @@ reload_cse_simplify_operands (rtx insn, rtx testreg)
             extension.  Punt on this for now.  */
          if (! set)
            continue;
-         /* If the destination is a also MEM or a STRICT_LOW_PART, no
+         /* If the destination is also a MEM or a STRICT_LOW_PART, no
             extension applies.
             Also, if there is an explicit extension, we don't have to
             worry about an implicit one.  */
@@ -721,14 +736,14 @@ reload_combine (void)
   FOR_EACH_BB_REVERSE (bb)
     {
       insn = BB_HEAD (bb);
-      if (GET_CODE (insn) == CODE_LABEL)
+      if (LABEL_P (insn))
        {
          HARD_REG_SET live;
 
          REG_SET_TO_HARD_REG_SET (live,
-                                  bb->global_live_at_start);
+                                  bb->il.rtl->global_live_at_start);
          compute_use_by_pseudos (&live,
-                                 bb->global_live_at_start);
+                                 bb->il.rtl->global_live_at_start);
          COPY_HARD_REG_SET (LABEL_LIVE (insn), live);
          IOR_HARD_REG_SET (ever_live_at_start, live);
        }
@@ -752,9 +767,9 @@ reload_combine (void)
       /* We cannot do our optimization across labels.  Invalidating all the use
         information we have would be costly, so we just note where the label
         is and then later disable any optimization that would cross it.  */
-      if (GET_CODE (insn) == CODE_LABEL)
+      if (LABEL_P (insn))
        last_label_ruid = reload_combine_ruid;
-      else if (GET_CODE (insn) == BARRIER)
+      else if (BARRIER_P (insn))
        for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
          if (! fixed_regs[r])
              reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
@@ -898,7 +913,7 @@ reload_combine (void)
 
       note_stores (PATTERN (insn), reload_combine_note_store, NULL);
 
-      if (GET_CODE (insn) == CALL_INSN)
+      if (CALL_P (insn))
        {
          rtx link;
 
@@ -932,7 +947,7 @@ reload_combine (void)
             }
 
        }
-      else if (GET_CODE (insn) == JUMP_INSN
+      else if (JUMP_P (insn)
               && GET_CODE (PATTERN (insn)) != RETURN)
        {
          /* Non-spill registers might be used at the call destination in
@@ -992,11 +1007,9 @@ reload_combine_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
 
   /* note_stores might have stripped a STRICT_LOW_PART, so we have to be
      careful with registers / register parts that are not full words.
-
-     Similarly for ZERO_EXTRACT and SIGN_EXTRACT.  */
+     Similarly for ZERO_EXTRACT.  */
   if (GET_CODE (set) != SET
       || GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
-      || GET_CODE (SET_DEST (set)) == SIGN_EXTRACT
       || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
     {
       for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
@@ -1057,8 +1070,7 @@ reload_combine_note_use (rtx *xp, rtx insn)
       if (REG_P (SET_DEST (x)))
        {
          /* No spurious CLOBBERs of pseudo registers may remain.  */
-         if (REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER)
-           abort ();
+         gcc_assert (REGNO (SET_DEST (x)) < FIRST_PSEUDO_REGISTER);
          return;
        }
       break;
@@ -1078,8 +1090,7 @@ reload_combine_note_use (rtx *xp, rtx insn)
        int nregs;
 
        /* No spurious USEs of pseudo registers may remain.  */
-       if (regno >= FIRST_PSEUDO_REGISTER)
-         abort ();
+       gcc_assert (regno < FIRST_PSEUDO_REGISTER);
 
        nregs = hard_regno_nregs[regno][GET_MODE (x)];
 
@@ -1192,7 +1203,7 @@ reload_cse_move2add (rtx first)
     {
       rtx pat, note;
 
-      if (GET_CODE (insn) == CODE_LABEL)
+      if (LABEL_P (insn))
        {
          move2add_last_label_luid = move2add_luid;
          /* We're going to increment move2add_luid twice after a
@@ -1233,10 +1244,8 @@ reload_cse_move2add (rtx first)
 
              if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
                {
-                 rtx new_src =
-                   GEN_INT (trunc_int_for_mode (INTVAL (src)
-                                                - reg_offset[regno],
-                                                GET_MODE (reg)));
+                 rtx new_src = gen_int_mode (INTVAL (src) - reg_offset[regno],
+                                             GET_MODE (reg));
                  /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
                     use (set (reg) (reg)) instead.
                     We don't delete this insn, nor do we convert it into a
@@ -1262,7 +1271,8 @@ reload_cse_move2add (rtx first)
                    {
                      enum machine_mode narrow_mode;
                      for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-                          narrow_mode != GET_MODE (reg);
+                          narrow_mode != VOIDmode
+                          && narrow_mode != GET_MODE (reg);
                           narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
                        {
                          if (have_insn_for (STRICT_LOW_PART, narrow_mode)
@@ -1273,9 +1283,8 @@ reload_cse_move2add (rtx first)
                            {
                              rtx narrow_reg = gen_rtx_REG (narrow_mode,
                                                            REGNO (reg));
-                             rtx narrow_src =
-                               GEN_INT (trunc_int_for_mode (INTVAL (src),
-                                                            narrow_mode));
+                             rtx narrow_src = gen_int_mode (INTVAL (src),
+                                                            narrow_mode);
                              rtx new_set =
                                gen_rtx_SET (VOIDmode,
                                             gen_rtx_STRICT_LOW_PART (VOIDmode,
@@ -1324,10 +1333,10 @@ reload_cse_move2add (rtx first)
                      HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
                      HOST_WIDE_INT regno_offset = reg_offset[regno];
                      rtx new_src =
-                       GEN_INT (trunc_int_for_mode (added_offset
-                                                    + base_offset
-                                                    - regno_offset,
-                                                    GET_MODE (reg)));
+                       gen_int_mode (added_offset
+                                     + base_offset
+                                     - regno_offset,
+                                     GET_MODE (reg));
                      int success = 0;
 
                      if (new_src == const0_rtx)
@@ -1375,13 +1384,14 @@ reload_cse_move2add (rtx first)
 
       /* If INSN is a conditional branch, we try to extract an
         implicit set out of it.  */
-      if (any_condjump_p (insn) && onlyjump_p (insn))
+      if (any_condjump_p (insn))
        {
          rtx cnd = fis_get_condition (insn);
 
          if (cnd != NULL_RTX
              && GET_CODE (cnd) == NE
              && REG_P (XEXP (cnd, 0))
+             && !reg_set_p (XEXP (cnd, 0), insn)
              /* The following two checks, which are also in
                 move2add_note_store, are intended to reduce the
                 number of calls to gen_rtx_SET to avoid memory
@@ -1398,7 +1408,7 @@ reload_cse_move2add (rtx first)
 
       /* If this is a CALL_INSN, all call used registers are stored with
         unknown values.  */
-      if (GET_CODE (insn) == CALL_INSN)
+      if (CALL_P (insn))
        {
          for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
            {
@@ -1445,10 +1455,9 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
 
   regno += REGNO (dst);
 
-  if (SCALAR_INT_MODE_P (mode)
+  if (SCALAR_INT_MODE_P (GET_MODE (dst))
       && hard_regno_nregs[regno][mode] == 1 && GET_CODE (set) == SET
       && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
-      && GET_CODE (SET_DEST (set)) != SIGN_EXTRACT
       && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
     {
       rtx src = SET_SRC (set);
@@ -1554,3 +1563,39 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
        reg_set_luid[i] = 0;
     }
 }
+\f
+static bool
+gate_handle_postreload (void)
+{
+  return (optimize > 0);
+}
+
+
+static void
+rest_of_handle_postreload (void)
+{
+  /* Do a very simple CSE pass over just the hard registers.  */
+  reload_cse_regs (get_insns ());
+  /* reload_cse_regs can eliminate potentially-trapping MEMs.
+     Remove any EH edges associated with them.  */
+  if (flag_non_call_exceptions)
+    purge_all_dead_edges ();
+}
+
+struct tree_opt_pass pass_postreload_cse =
+{
+  "postreload",                         /* name */
+  gate_handle_postreload,               /* gate */
+  rest_of_handle_postreload,            /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_RELOAD_CSE_REGS,                   /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'o'                                   /* letter */
+};
+