OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / postreload.c
index 4ac2137..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;
@@ -816,8 +823,7 @@ reload_combine_purge_reg_uses_after_ruid (unsigned regno, int ruid)
 
 /* Find the use of REGNO with the ruid that is highest among those
    lower than RUID_LIMIT, and return it if it is the only use of this
-   reg in the insn (or if the insn is a debug insn).  Return NULL
-   otherwise.  */
+   reg in the insn.  Return NULL otherwise.  */
 
 static struct reg_use *
 reload_combine_closest_single_use (unsigned regno, int ruid_limit)
@@ -838,9 +844,9 @@ reload_combine_closest_single_use (unsigned regno, int ruid_limit)
       if (this_ruid > best_ruid)
        {
          best_ruid = this_ruid;
-         retval = reg_state[regno].reg_use + i;
+         retval = use;
        }
-      else if (this_ruid == best_ruid && !DEBUG_INSN_P (use->insn))
+      else if (this_ruid == best_ruid)
        retval = NULL;
     }
   if (last_label_ruid >= best_ruid)
@@ -866,11 +872,66 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx from, rtx to)
        continue;
       
       t = INSN_VAR_LOCATION_LOC (insn);
-      t = simplify_replace_rtx (t, reg, copy_rtx (replacement));
+      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.
@@ -938,16 +999,11 @@ reload_combine_recognize_const_pattern (rtx insn)
        /* Start the search for the next use from here.  */
        from_ruid = use->ruid;
 
-      /* We'll fix up DEBUG_INSNs after we're done.  */
-      if (use && DEBUG_INSN_P (use->insn))
-       continue;
-
       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)
@@ -959,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
 
-         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, 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);
+         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 (must_move_add)
-                       {
-                         add_moved_after_insn = use_insn;
-                         add_moved_after_ruid = use_ruid;
-                       }
-                     continue;
-                   }
-               }
-           }
-         else
+         /* 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)
            {
-             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 (use->containing_mem == NULL_RTX)
+               delete_add = true;
+             else
+               break;
+           }
 
-                 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);
 
@@ -1102,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;
@@ -1134,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);
@@ -1150,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))
        {
@@ -1201,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;
            }
        }
@@ -1214,7 +1235,6 @@ static void
 reload_combine (void)
 {
   rtx insn, prev;
-  int i;
   basic_block bb;
   unsigned int r;
   int min_labelno, n_labels;
@@ -1244,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
@@ -1290,6 +1302,7 @@ reload_combine (void)
 
   for (insn = get_last_insn (); insn; insn = prev)
     {
+      bool control_flow_insn;
       rtx note;
 
       prev = PREV_INSN (insn);
@@ -1300,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 (! NONDEBUG_INSN_P (insn))
        continue;
 
       reload_combine_ruid++;
 
-      if (control_flow_insn_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)
@@ -1337,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)
                      {
@@ -1350,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.  */
@@ -1365,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;
@@ -1408,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);
@@ -1511,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
@@ -1602,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).
@@ -1638,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;
+               }
            }
        }
     }
@@ -1698,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
@@ -1721,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;
 
@@ -1846,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);
@@ -1872,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);
@@ -2097,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);
@@ -2220,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 */
  }
 };