OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / postreload.c
index cd504e2..5c18912 100644 (file)
@@ -1,7 +1,7 @@
 /* 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, 2005, 2006, 2007, 2008, 2009,
-   2010 Free Software Foundation, Inc.
+   2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -41,9 +41,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "cselib.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "except.h"
 #include "tree.h"
+#include "target.h"
 #include "timevar.h"
 #include "tree-pass.h"
 #include "df.h"
@@ -112,7 +112,8 @@ reload_cse_simplify (rtx insn, rtx testreg)
          if (REG_P (value)
              && ! REG_FUNCTION_VALUE_P (value))
            value = 0;
-         delete_insn_and_edges (insn);
+         if (check_for_inc_dec (insn))
+           delete_insn_and_edges (insn);
          return;
        }
 
@@ -163,7 +164,8 @@ reload_cse_simplify (rtx insn, rtx testreg)
 
       if (i < 0)
        {
-         delete_insn_and_edges (insn);
+         if (check_for_inc_dec (insn))
+           delete_insn_and_edges (insn);
          /* We're done with this insn.  */
          return;
        }
@@ -231,7 +233,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
   int did_change = 0;
   int dreg;
   rtx src;
-  enum reg_class dclass;
+  reg_class_t dclass;
   int old_cost;
   cselib_val *val;
   struct elt_loc_list *l;
@@ -262,7 +264,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
     return 0;
 #endif
 
-  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0, VOIDmode);
   if (! val)
     return 0;
 
@@ -273,7 +275,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
     old_cost = register_move_cost (GET_MODE (src),
                                   REGNO_REG_CLASS (REGNO (src)), dclass);
   else
-    old_cost = rtx_cost (src, SET, speed);
+    old_cost = set_src_cost (src, speed);
 
   for (l = val->locs; l; l = l->next)
     {
@@ -308,7 +310,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
              this_rtx = GEN_INT (this_val);
            }
 #endif
-         this_cost = rtx_cost (this_rtx, SET, speed);
+         this_cost = set_src_cost (this_rtx, speed);
        }
       else if (REG_P (this_rtx))
        {
@@ -316,7 +318,7 @@ reload_cse_simplify_set (rtx set, rtx insn)
          if (extend_op != UNKNOWN)
            {
              this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
-             this_cost = rtx_cost (this_rtx, SET, speed);
+             this_cost = set_src_cost (this_rtx, speed);
            }
          else
 #endif
@@ -476,7 +478,9 @@ reload_cse_simplify_operands (rtx insn, rtx testreg)
            continue;
        }
 #endif /* LOAD_EXTEND_OP */
-      v = cselib_lookup (op, recog_data.operand_mode[i], 0);
+      if (side_effects_p (op))
+       continue;
+      v = cselib_lookup (op, recog_data.operand_mode[i], 0, VOIDmode);
       if (! v)
        continue;
 
@@ -527,7 +531,7 @@ reload_cse_simplify_operands (rtx insn, rtx testreg)
          if (! TEST_HARD_REG_BIT (equiv_regs[i], regno))
            continue;
 
-         SET_REGNO (testreg, regno);
+         SET_REGNO_RAW (testreg, regno);
          PUT_MODE (testreg, mode);
 
          /* We found a register equal to this operand.  Now look for all
@@ -572,12 +576,15 @@ reload_cse_simplify_operands (rtx insn, rtx testreg)
                     alternative yet and the operand being replaced is not
                     a cheap CONST_INT.  */
                  if (op_alt_regno[i][j] == -1
+                     && recog_data.alternative_enabled_p[j]
                      && reg_fits_class_p (testreg, rclass, 0, mode)
                      && (!CONST_INT_P (recog_data.operand[i])
-                         || (rtx_cost (recog_data.operand[i], SET,
-                                       optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)))
-                             > rtx_cost (testreg, SET,
-                                       optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn))))))
+                         || (set_src_cost (recog_data.operand[i],
+                                           optimize_bb_for_speed_p
+                                            (BLOCK_FOR_INSN (insn)))
+                             > set_src_cost (testreg,
+                                             optimize_bb_for_speed_p
+                                              (BLOCK_FOR_INSN (insn))))))
                    {
                      alternative_nregs[j]++;
                      op_alt_regno[i][j] = regno;
@@ -830,13 +837,14 @@ reload_combine_closest_single_use (unsigned regno, int ruid_limit)
   retval = NULL;
   for (i = use_idx; i < RELOAD_COMBINE_MAX_USES; i++)
     {
-      int this_ruid = reg_state[regno].reg_use[i].ruid;
+      struct reg_use *use = reg_state[regno].reg_use + i; 
+      int this_ruid = use->ruid;
       if (this_ruid >= ruid_limit)
        continue;
       if (this_ruid > best_ruid)
        {
          best_ruid = this_ruid;
-         retval = reg_state[regno].reg_use + i;
+         retval = use;
        }
       else if (this_ruid == best_ruid)
        retval = NULL;
@@ -846,6 +854,84 @@ reload_combine_closest_single_use (unsigned regno, int ruid_limit)
   return retval;
 }
 
+/* After we've moved an add insn, fix up any debug insns that occur
+   between the old location of the add and the new location.  REG is
+   the destination register of the add insn; REPLACEMENT is the
+   SET_SRC of the add.  FROM and TO specify the range in which we
+   should make this change on debug insns.  */
+
+static void
+fixup_debug_insns (rtx reg, rtx replacement, rtx from, rtx to)
+{
+  rtx insn;
+  for (insn = from; insn != to; insn = NEXT_INSN (insn))
+    {
+      rtx t;
+
+      if (!DEBUG_INSN_P (insn))
+       continue;
+      
+      t = INSN_VAR_LOCATION_LOC (insn);
+      t = simplify_replace_rtx (t, reg, replacement);
+      validate_change (insn, &INSN_VAR_LOCATION_LOC (insn), t, 0);
+    }
+}
+
+/* Subroutine of reload_combine_recognize_const_pattern.  Try to replace REG
+   with SRC in the insn described by USE, taking costs into account.  Return
+   true if we made the replacement.  */
+
+static bool
+try_replace_in_use (struct reg_use *use, rtx reg, rtx src)
+{
+  rtx use_insn = use->insn;
+  rtx mem = use->containing_mem;
+  bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_insn));
+
+  if (mem != NULL_RTX)
+    {
+      addr_space_t as = MEM_ADDR_SPACE (mem);
+      rtx oldaddr = XEXP (mem, 0);
+      rtx newaddr = NULL_RTX;
+      int old_cost = address_cost (oldaddr, GET_MODE (mem), as, speed);
+      int new_cost;
+
+      newaddr = simplify_replace_rtx (oldaddr, reg, src);
+      if (memory_address_addr_space_p (GET_MODE (mem), newaddr, as))
+       {
+         XEXP (mem, 0) = newaddr;
+         new_cost = address_cost (newaddr, GET_MODE (mem), as, speed);
+         XEXP (mem, 0) = oldaddr;
+         if (new_cost <= old_cost
+             && validate_change (use_insn,
+                                 &XEXP (mem, 0), newaddr, 0))
+           return true;
+       }
+    }
+  else
+    {
+      rtx new_set = single_set (use_insn);
+      if (new_set
+         && REG_P (SET_DEST (new_set))
+         && GET_CODE (SET_SRC (new_set)) == PLUS
+         && REG_P (XEXP (SET_SRC (new_set), 0))
+         && CONSTANT_P (XEXP (SET_SRC (new_set), 1)))
+       {
+         rtx new_src;
+         int old_cost = set_src_cost (SET_SRC (new_set), speed);
+
+         gcc_assert (rtx_equal_p (XEXP (SET_SRC (new_set), 0), reg));
+         new_src = simplify_replace_rtx (SET_SRC (new_set), reg, src);
+
+         if (set_src_cost (new_src, speed) <= old_cost
+             && validate_change (use_insn, &SET_SRC (new_set),
+                                 new_src, 0))
+           return true;
+       }
+    }
+  return false;
+}
+
 /* Called by reload_combine when scanning INSN.  This function tries to detect
    patterns where a constant is added to a register, and the result is used
    in an address.
@@ -915,13 +1001,12 @@ reload_combine_recognize_const_pattern (rtx insn)
 
       if (use && GET_MODE (*use->usep) == Pmode)
        {
+         bool delete_add = false;
          rtx use_insn = use->insn;
          int use_ruid = use->ruid;
-         rtx mem = use->containing_mem;
-         bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_insn));
 
          /* Avoid moving the add insn past a jump.  */
-         if (must_move_add && use_ruid < last_jump_ruid)
+         if (must_move_add && use_ruid <= last_jump_ruid)
            break;
 
          /* If the add clobbers another hard reg in parallel, don't move
@@ -930,88 +1015,50 @@ reload_combine_recognize_const_pattern (rtx insn)
              && reg_state[clobbered_regno].real_store_ruid >= use_ruid)
            break;
 
-         /* Avoid moving a use of ADDREG past a point where it
-            is stored.  */
-         if (reg_state[REGNO (addreg)].store_ruid >= use_ruid)
+#ifdef HAVE_cc0
+         /* Do not separate cc0 setter and cc0 user on HAVE_cc0 targets.  */
+         if (must_move_add && sets_cc0_p (PATTERN (use_insn)))
+           break;
+#endif
+
+         gcc_assert (reg_state[regno].store_ruid <= use_ruid);
+         /* Avoid moving a use of ADDREG past a point where it is stored.  */
+         if (reg_state[REGNO (addreg)].store_ruid > use_ruid)
            break;
 
-         if (mem != NULL_RTX)
+         /* We also must not move the addition past an insn that sets
+            the same register, unless we can combine two add insns.  */
+         if (must_move_add && reg_state[regno].store_ruid == use_ruid)
            {
-             addr_space_t as = MEM_ADDR_SPACE (mem);
-             rtx oldaddr = XEXP (mem, 0);
-             rtx newaddr = NULL_RTX;
-             int old_cost = address_cost (oldaddr, GET_MODE (mem), as, speed);
-             int new_cost;
-
-             newaddr = simplify_replace_rtx (oldaddr, reg, copy_rtx (src));
-             if (memory_address_addr_space_p (GET_MODE (mem), newaddr, as))
-               {
-                 XEXP (mem, 0) = newaddr;
-                 new_cost = address_cost (newaddr, GET_MODE (mem), as, speed);
-                 XEXP (mem, 0) = oldaddr;
-                 if (new_cost <= old_cost
-                     && validate_change (use_insn,
-                                         &XEXP (mem, 0), newaddr, 0))
-                   {
-                     reload_combine_purge_insn_uses (use_insn);
-                     reload_combine_note_use (&PATTERN (use_insn), use_insn,
-                                              use_ruid, NULL_RTX);
-
-                     if (must_move_add)
-                       {
-                         add_moved_after_insn = use_insn;
-                         add_moved_after_ruid = use_ruid;
-                       }
-                     continue;
-                   }
-               }
+             if (use->containing_mem == NULL_RTX)
+               delete_add = true;
+             else
+               break;
            }
-         else
-           {
-             rtx new_set = single_set (use_insn);
-             if (new_set
-                 && REG_P (SET_DEST (new_set))
-                 && GET_CODE (SET_SRC (new_set)) == PLUS
-                 && REG_P (XEXP (SET_SRC (new_set), 0))
-                 && CONSTANT_P (XEXP (SET_SRC (new_set), 1)))
-               {
-                 rtx new_src;
-                 int old_cost = rtx_cost (SET_SRC (new_set), SET, speed);
 
-                 gcc_assert (rtx_equal_p (XEXP (SET_SRC (new_set), 0), reg));
-                 new_src = simplify_replace_rtx (SET_SRC (new_set), reg,
-                                                 copy_rtx (src));
-
-                 if (rtx_cost (new_src, SET, speed) <= old_cost
-                     && validate_change (use_insn, &SET_SRC (new_set),
-                                         new_src, 0))
-                   {
-                     reload_combine_purge_insn_uses (use_insn);
-                     reload_combine_note_use (&SET_SRC (new_set), use_insn,
-                                              use_ruid, NULL_RTX);
+         if (try_replace_in_use (use, reg, src))
+           {
+             reload_combine_purge_insn_uses (use_insn);
+             reload_combine_note_use (&PATTERN (use_insn), use_insn,
+                                      use_ruid, NULL_RTX);
 
-                     if (must_move_add)
-                       {
-                         /* See if that took care of the add insn.  */
-                         if (rtx_equal_p (SET_DEST (new_set), reg))
-                           {
-                             delete_insn (insn);
-                             return true;
-                           }
-                         else
-                           {
-                             add_moved_after_insn = use_insn;
-                             add_moved_after_ruid = use_ruid;
-                           }
-                       }
-                     continue;
-                   }
+             if (delete_add)
+               {
+                 fixup_debug_insns (reg, src, insn, use_insn);
+                 delete_insn (insn);
+                 return true;
                }
+             if (must_move_add)
+               {
+                 add_moved_after_insn = use_insn;
+                 add_moved_after_ruid = use_ruid;
+               }
+             continue;
            }
-         /* If we get here, we couldn't handle this use.  */
-         if (must_move_add)
-           break;
        }
+      /* If we get here, we couldn't handle this use.  */
+      if (must_move_add)
+       break;
     }
   while (use);
 
@@ -1019,6 +1066,8 @@ reload_combine_recognize_const_pattern (rtx insn)
     /* Process the add normally.  */
     return false;
 
+  fixup_debug_insns (reg, src, insn, add_moved_after_insn);
+
   reorder_insns (insn, insn, add_moved_after_insn);
   reload_combine_purge_reg_uses_after_ruid (regno, add_moved_after_ruid);
   reload_combine_split_ruids (add_moved_after_ruid - 1);
@@ -1071,10 +1120,12 @@ reload_combine_recognize_pattern (rtx insn)
       && REG_P (XEXP (src, 1))
       && rtx_equal_p (XEXP (src, 0), reg)
       && !rtx_equal_p (XEXP (src, 1), reg)
+      && reg_state[regno].use_index >= 0
+      && reg_state[regno].use_index < RELOAD_COMBINE_MAX_USES
       && last_label_ruid < reg_state[regno].use_ruid)
     {
       rtx base = XEXP (src, 1);
-      rtx prev = prev_nonnote_insn (insn);
+      rtx prev = prev_nonnote_nondebug_insn (insn);
       rtx prev_set = prev ? single_set (prev) : NULL_RTX;
       rtx index_reg = NULL_RTX;
       rtx reg_sum = NULL_RTX;
@@ -1103,7 +1154,11 @@ reload_combine_recognize_pattern (rtx insn)
              if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i)
                  && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
                  && reg_state[i].store_ruid <= reg_state[regno].use_ruid
-                 && hard_regno_nregs[i][GET_MODE (reg)] == 1)
+                 && (call_used_regs[i] || df_regs_ever_live_p (i))
+                 && (!frame_pointer_needed || i != HARD_FRAME_POINTER_REGNUM)
+                 && !fixed_regs[i] && !global_regs[i]
+                 && hard_regno_nregs[i][GET_MODE (reg)] == 1
+                 && targetm.hard_regno_scratch_ok (i))
                {
                  index_reg = gen_rtx_REG (GET_MODE (reg), i);
                  reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
@@ -1119,7 +1174,6 @@ reload_combine_recognize_pattern (rtx insn)
          && prev_set
          && CONST_INT_P (SET_SRC (prev_set))
          && rtx_equal_p (SET_DEST (prev_set), reg)
-         && reg_state[regno].use_index >= 0
          && (reg_state[REGNO (base)].store_ruid
              <= reg_state[regno].use_ruid))
        {
@@ -1145,20 +1199,21 @@ reload_combine_recognize_pattern (rtx insn)
 
          if (apply_change_group ())
            {
+             struct reg_use *lowest_ruid = NULL;
+
              /* For every new use of REG_SUM, we have to record the use
                 of BASE therein, i.e. operand 1.  */
              for (i = reg_state[regno].use_index;
                   i < RELOAD_COMBINE_MAX_USES; i++)
-               reload_combine_note_use
-                 (&XEXP (*reg_state[regno].reg_use[i].usep, 1),
-                  reg_state[regno].reg_use[i].insn,
-                  reg_state[regno].reg_use[i].ruid,
-                  reg_state[regno].reg_use[i].containing_mem);
+               {
+                 struct reg_use *use = reg_state[regno].reg_use + i;
+                 reload_combine_note_use (&XEXP (*use->usep, 1), use->insn,
+                                          use->ruid, use->containing_mem);
+                 if (lowest_ruid == NULL || use->ruid < lowest_ruid->ruid)
+                   lowest_ruid = use;
+               }
 
-             if (reg_state[REGNO (base)].use_ruid
-                 > reg_state[regno].use_ruid)
-               reg_state[REGNO (base)].use_ruid
-                 = reg_state[regno].use_ruid;
+             fixup_debug_insns (reg, reg_sum, insn, lowest_ruid->insn);
 
              /* Delete the reg-reg addition.  */
              delete_insn (insn);
@@ -1169,8 +1224,6 @@ reload_combine_recognize_pattern (rtx insn)
                remove_reg_equal_equiv_notes (prev);
 
              reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
-             reg_state[REGNO (index_reg)].store_ruid
-               = reload_combine_ruid;
              return true;
            }
        }
@@ -1182,7 +1235,6 @@ static void
 reload_combine (void)
 {
   rtx insn, prev;
-  int i;
   basic_block bb;
   unsigned int r;
   int min_labelno, n_labels;
@@ -1212,14 +1264,6 @@ reload_combine (void)
        }
     }
 
-#if 0
-  /* If reg+reg can be used in offsetable memory addresses, the main chunk of
-     reload has already used it where appropriate, so there is no use in
-     trying to generate it now.  */
-  if (double_reg_address_ok || last_index_reg == -1)
-    return;
-#endif
-
   /* Set up LABEL_LIVE and EVER_LIVE_AT_START.  The register lifetime
      information is a bit fuzzy immediately after reload, but it's
      still good enough to determine which registers are live at a jump
@@ -1258,6 +1302,7 @@ reload_combine (void)
 
   for (insn = get_last_insn (); insn; insn = prev)
     {
+      bool control_flow_insn;
       rtx note;
 
       prev = PREV_INSN (insn);
@@ -1268,16 +1313,28 @@ reload_combine (void)
       if (LABEL_P (insn))
        last_label_ruid = reload_combine_ruid;
       else if (BARRIER_P (insn))
-       for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
-         if (! fixed_regs[r])
+       {
+         /* Crossing a barrier resets all the use information.  */
+         for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+           if (! fixed_regs[r])
              reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
+       }
+      else if (INSN_P (insn) && volatile_insn_p (PATTERN (insn)))
+       /* Optimizations across insns being marked as volatile must be
+          prevented.  All the usage information is invalidated
+          here.  */
+       for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+         if (! fixed_regs[r]
+             && reg_state[r].use_index != RELOAD_COMBINE_MAX_USES)
+           reg_state[r].use_index = -1;
 
-      if (! INSN_P (insn))
+      if (! NONDEBUG_INSN_P (insn))
        continue;
 
       reload_combine_ruid++;
 
-      if (JUMP_P (insn))
+      control_flow_insn = control_flow_insn_p (insn);
+      if (control_flow_insn)
        last_jump_ruid = reload_combine_ruid;
 
       if (reload_combine_recognize_const_pattern (insn)
@@ -1305,9 +1362,9 @@ reload_combine (void)
                {
                  unsigned int i;
                  unsigned int start_reg = REGNO (usage_rtx);
-                 unsigned int num_regs =
-                       hard_regno_nregs[start_reg][GET_MODE (usage_rtx)];
-                 unsigned int end_reg  = start_reg + num_regs - 1;
+                 unsigned int num_regs
+                   = hard_regno_nregs[start_reg][GET_MODE (usage_rtx)];
+                 unsigned int end_reg = start_reg + num_regs - 1;
                  for (i = start_reg; i <= end_reg; i++)
                    if (GET_CODE (XEXP (link, 0)) == CLOBBER)
                      {
@@ -1318,10 +1375,9 @@ reload_combine (void)
                      reg_state[i].use_index = -1;
                 }
             }
-
        }
-      else if (JUMP_P (insn)
-              && GET_CODE (PATTERN (insn)) != RETURN)
+
+      if (control_flow_insn && GET_CODE (PATTERN (insn)) != RETURN)
        {
          /* Non-spill registers might be used at the call destination in
             some unknown fashion, so we have to mark the unknown use.  */
@@ -1333,20 +1389,19 @@ reload_combine (void)
          else
            live = &ever_live_at_start;
 
-         for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
-           if (TEST_HARD_REG_BIT (*live, i))
-             reg_state[i].use_index = -1;
+         for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+           if (TEST_HARD_REG_BIT (*live, r))
+             reg_state[r].use_index = -1;
        }
 
-      reload_combine_note_use (&PATTERN (insn), insn,
-                              reload_combine_ruid, NULL_RTX);
+      reload_combine_note_use (&PATTERN (insn), insn, reload_combine_ruid,
+                              NULL_RTX);
+
       for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
        {
-         if (REG_NOTE_KIND (note) == REG_INC
-             && REG_P (XEXP (note, 0)))
+         if (REG_NOTE_KIND (note) == REG_INC && REG_P (XEXP (note, 0)))
            {
              int regno = REGNO (XEXP (note, 0));
-
              reg_state[regno].store_ruid = reload_combine_ruid;
              reg_state[regno].real_store_ruid = reload_combine_ruid;
              reg_state[regno].use_index = -1;
@@ -1376,6 +1431,32 @@ reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
                                   GET_MODE (dst));
       dst = SUBREG_REG (dst);
     }
+
+  /* Some targets do argument pushes without adding REG_INC notes.  */
+
+  if (MEM_P (dst))
+    {
+      dst = XEXP (dst, 0);
+      if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC
+         || GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC
+         || GET_CODE (dst) == PRE_MODIFY || GET_CODE (dst) == POST_MODIFY)
+       {
+         regno = REGNO (XEXP (dst, 0));
+         mode = GET_MODE (XEXP (dst, 0));
+         for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
+           {
+             /* We could probably do better, but for now mark the register
+                as used in an unknown fashion and set/clobbered at this
+                insn.  */
+             reg_state[i].use_index = -1;
+             reg_state[i].store_ruid = reload_combine_ruid;
+             reg_state[i].real_store_ruid = reload_combine_ruid;
+           }
+       }
+      else
+        return;
+    }
+
   if (!REG_P (dst))
     return;
   regno += REGNO (dst);
@@ -1479,6 +1560,11 @@ reload_combine_note_use (rtx *xp, rtx insn, int ruid, rtx containing_mem)
            return;
          }
 
+       /* We may be called to update uses in previously seen insns.
+          Don't add uses beyond the last store we saw.  */
+       if (ruid < reg_state[regno].store_ruid)
+         return;
+
        /* If this register is already used in some unknown fashion, we
           can't do anything.
           If we decrement the index from zero to -1, we can't store more
@@ -1495,8 +1581,14 @@ reload_combine_note_use (rtx *xp, rtx insn, int ruid, rtx containing_mem)
            reg_state[regno].all_offsets_match = true;
            reg_state[regno].use_ruid = ruid;
          }
-       else if (! rtx_equal_p (offset, reg_state[regno].offset))
-         reg_state[regno].all_offsets_match = false;
+       else
+         {
+           if (reg_state[regno].use_ruid > ruid)
+             reg_state[regno].use_ruid = ruid;
+
+           if (! rtx_equal_p (offset, reg_state[regno].offset))
+             reg_state[regno].all_offsets_match = false;
+         }
 
        reg_state[regno].reg_use[use_index].insn = insn;
        reg_state[regno].reg_use[use_index].ruid = ruid;
@@ -1564,8 +1656,7 @@ static int move2add_last_label_luid;
 #define MODES_OK_FOR_MOVE2ADD(OUTMODE, INMODE) \
   (GET_MODE_SIZE (OUTMODE) == GET_MODE_SIZE (INMODE) \
    || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \
-       && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \
-                                GET_MODE_BITSIZE (INMODE))))
+       && TRULY_NOOP_TRUNCATION_MODES_P (OUTMODE, INMODE)))
 
 /* This function is called with INSN that sets REG to (SYM + OFF),
    while REG is known to already have value (SYM + offset).
@@ -1600,39 +1691,45 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn)
       if (INTVAL (off) == reg_offset [regno])
        changed = validate_change (insn, &SET_SRC (pat), reg, 0);
     }
-  else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed)
-          && have_add2_insn (reg, new_src))
+  else
     {
+      struct full_rtx_costs oldcst, newcst;
       rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
-      changed = validate_change (insn, &SET_SRC (pat), tem, 0);
-    }
-  else if (sym == NULL_RTX && GET_MODE (reg) != BImode)
-    {
-      enum machine_mode narrow_mode;
-      for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          narrow_mode != VOIDmode
-            && narrow_mode != GET_MODE (reg);
-          narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
+
+      get_full_set_rtx_cost (pat, &oldcst);
+      SET_SRC (pat) = tem;
+      get_full_set_rtx_cost (pat, &newcst);
+      SET_SRC (pat) = src;
+
+      if (costs_lt_p (&newcst, &oldcst, speed)
+         && have_add2_insn (reg, new_src))
+       changed = validate_change (insn, &SET_SRC (pat), tem, 0);       
+      else if (sym == NULL_RTX && GET_MODE (reg) != BImode)
        {
-         if (have_insn_for (STRICT_LOW_PART, narrow_mode)
-             && ((reg_offset[regno]
-                  & ~GET_MODE_MASK (narrow_mode))
-                 == (INTVAL (off)
-                     & ~GET_MODE_MASK (narrow_mode))))
+         enum machine_mode narrow_mode;
+         for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+              narrow_mode != VOIDmode
+                && narrow_mode != GET_MODE (reg);
+              narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
            {
-             rtx narrow_reg = gen_rtx_REG (narrow_mode,
-                                           REGNO (reg));
-             rtx narrow_src = gen_int_mode (INTVAL (off),
-                                            narrow_mode);
-             rtx new_set =
-               gen_rtx_SET (VOIDmode,
-                            gen_rtx_STRICT_LOW_PART (VOIDmode,
-                                                     narrow_reg),
-                            narrow_src);
-             changed = validate_change (insn, &PATTERN (insn),
-                                        new_set, 0);
-             if (changed)
-               break;
+             if (have_insn_for (STRICT_LOW_PART, narrow_mode)
+                 && ((reg_offset[regno] & ~GET_MODE_MASK (narrow_mode))
+                     == (INTVAL (off) & ~GET_MODE_MASK (narrow_mode))))
+               {
+                 rtx narrow_reg = gen_rtx_REG (narrow_mode,
+                                               REGNO (reg));
+                 rtx narrow_src = gen_int_mode (INTVAL (off),
+                                                narrow_mode);
+                 rtx new_set
+                   = gen_rtx_SET (VOIDmode,
+                                  gen_rtx_STRICT_LOW_PART (VOIDmode,
+                                                           narrow_reg),
+                                  narrow_src);
+                 changed = validate_change (insn, &PATTERN (insn),
+                                            new_set, 0);
+                 if (changed)
+                   break;
+               }
            }
        }
     }
@@ -1660,11 +1757,18 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
   rtx pat = PATTERN (insn);
   rtx src = SET_SRC (pat);
   int regno = REGNO (reg);
-  int min_cost = INT_MAX;
   int min_regno = 0;
   bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
   int i;
   bool changed = false;
+  struct full_rtx_costs oldcst, newcst, mincst;
+  rtx plus_expr;
+
+  init_costs_to_max (&mincst);
+  get_full_set_rtx_cost (pat, &oldcst);
+
+  plus_expr = gen_rtx_PLUS (GET_MODE (reg), reg, const0_rtx);
+  SET_SRC (pat) = plus_expr;
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (reg_set_luid[i] > move2add_last_label_luid
@@ -1683,22 +1787,25 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
           no-op moves.  */
        if (new_src == const0_rtx)
          {
-           min_cost = 0;
+           init_costs_to_zero (&mincst);
            min_regno = i;
            break;
          }
        else
          {
-           int cost = rtx_cost (new_src, PLUS, speed);
-           if (cost < min_cost)
+           XEXP (plus_expr, 1) = new_src;
+           get_full_set_rtx_cost (pat, &newcst);
+
+           if (costs_lt_p (&newcst, &mincst, speed))
              {
-               min_cost = cost;
+               mincst = newcst;
                min_regno = i;
              }
          }
       }
+  SET_SRC (pat) = src;
 
-  if (min_cost < rtx_cost (src, SET, speed))
+  if (costs_lt_p (&mincst, &oldcst, speed))
     {
       rtx tem;
 
@@ -1808,7 +1915,7 @@ reload_cse_move2add (rtx first)
                       && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg),
                                                 reg_mode[REGNO (src)]))
                {
-                 rtx next = next_nonnote_insn (insn);
+                 rtx next = next_nonnote_nondebug_insn (insn);
                  rtx set = NULL_RTX;
                  if (next)
                    set = single_set (next);
@@ -1834,18 +1941,26 @@ reload_cse_move2add (rtx first)
                        /* See above why we create (set (reg) (reg)) here.  */
                        success
                          = validate_change (next, &SET_SRC (set), reg, 0);
-                     else if ((rtx_cost (new_src, PLUS, speed)
-                               < COSTS_N_INSNS (1) + rtx_cost (src3, SET, speed))
-                              && have_add2_insn (reg, new_src))
+                     else
                        {
-                         rtx newpat = gen_rtx_SET (VOIDmode,
-                                                   reg,
-                                                   gen_rtx_PLUS (GET_MODE (reg),
-                                                                 reg,
-                                                                 new_src));
-                         success
-                           = validate_change (next, &PATTERN (next),
-                                              newpat, 0);
+                         rtx old_src = SET_SRC (set);
+                         struct full_rtx_costs oldcst, newcst;
+                         rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
+
+                         get_full_set_rtx_cost (set, &oldcst);
+                         SET_SRC (set) = tem;
+                         get_full_set_src_cost (tem, &newcst);
+                         SET_SRC (set) = old_src;
+                         costs_add_n_insns (&oldcst, 1);
+
+                         if (costs_lt_p (&newcst, &oldcst, speed)
+                             && have_add2_insn (reg, new_src))
+                           {
+                             rtx newpat = gen_rtx_SET (VOIDmode, reg, tem);
+                             success
+                               = validate_change (next, &PATTERN (next),
+                                                  newpat, 0);
+                           }
                        }
                      if (success)
                        delete_insn (insn);
@@ -2059,15 +2174,17 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
                       && (MODES_OK_FOR_MOVE2ADD
                           (dst_mode, reg_mode[REGNO (XEXP (src, 1))])))
                {
-                 if (reg_base_reg[REGNO (XEXP (src, 1))] < 0)
+                 if (reg_base_reg[REGNO (XEXP (src, 1))] < 0
+                     && reg_symbol_ref[REGNO (XEXP (src, 1))] == NULL_RTX)
                    offset = reg_offset[REGNO (XEXP (src, 1))];
                  /* Maybe the first register is known to be a
                     constant.  */
                  else if (reg_set_luid[REGNO (base_reg)]
                           > move2add_last_label_luid
                           && (MODES_OK_FOR_MOVE2ADD
-                              (dst_mode, reg_mode[REGNO (XEXP (src, 1))]))
-                          && reg_base_reg[REGNO (base_reg)] < 0)
+                              (dst_mode, reg_mode[REGNO (base_reg)]))
+                          && reg_base_reg[REGNO (base_reg)] < 0
+                          && reg_symbol_ref[REGNO (base_reg)] == NULL_RTX)
                    {
                      offset = reg_offset[REGNO (base_reg)];
                      base_reg = XEXP (src, 1);
@@ -2182,6 +2299,6 @@ struct rtl_opt_pass pass_postreload_cse =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_dump_func                        /* todo_flags_finish */
+  0                                     /* todo_flags_finish */
  }
 };