OSDN Git Service

PR debug/46307
[pf3gnuchains/gcc-fork.git] / gcc / postreload.c
index 9a05cbc..1fc9bfc 100644 (file)
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "except.h"
 #include "tree.h"
+#include "target.h"
 #include "timevar.h"
 #include "tree-pass.h"
 #include "df.h"
@@ -527,7 +528,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,6 +573,7 @@ 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,
@@ -816,8 +818,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 +839,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)
@@ -848,42 +849,82 @@ 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.  REGNO is the destination
-   register of the add insn; REG is the corresponding RTX.  REPLACEMENT is
-   the SET_SRC of the add.  MIN_RUID specifies the ruid of the insn after
-   which we've placed the add, we ignore any debug insns after it.  */
+/* 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 (unsigned regno, rtx reg, rtx replacement, int min_ruid)
+fixup_debug_insns (rtx reg, rtx replacement, rtx from, rtx to)
 {
-  struct reg_use *use;
-  int from = reload_combine_ruid;
-  for (;;)
+  rtx insn;
+  for (insn = from; insn != to; insn = NEXT_INSN (insn))
     {
       rtx t;
-      rtx use_insn = NULL_RTX;
-      if (from < min_ruid)
-       break;
-      use = reload_combine_closest_single_use (regno, from);
-      if (use)
+
+      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))
        {
-         from = use->ruid;
-         use_insn = use->insn;
+         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 = 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, src);
+
+         if (rtx_cost (new_src, SET, speed) <= old_cost
+             && validate_change (use_insn, &SET_SRC (new_set),
+                                 new_src, 0))
+           return true;
        }
-      else
-       break;
-      
-      if (NONDEBUG_INSN_P (use->insn))
-       continue;
-      t = INSN_VAR_LOCATION_LOC (use_insn);
-      t = simplify_replace_rtx (t, reg, copy_rtx (replacement));
-      validate_change (use->insn,
-                      &INSN_VAR_LOCATION_LOC (use->insn), t, 0);
-      reload_combine_purge_insn_uses (use_insn);
-      reload_combine_note_use (&PATTERN (use_insn), use_insn,
-                              use->ruid, NULL_RTX);
     }
+  return false;
 }
 
 /* Called by reload_combine when scanning INSN.  This function tries to detect
@@ -953,16 +994,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)
@@ -974,88 +1010,44 @@ 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)
+         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);
 
@@ -1063,8 +1055,8 @@ reload_combine_recognize_const_pattern (rtx insn)
     /* Process the add normally.  */
     return false;
 
-  fixup_debug_insns (regno, reg, src, add_moved_after_ruid);
-  
+  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);
@@ -1117,10 +1109,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;
@@ -1149,7 +1143,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);
@@ -1165,7 +1163,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))
        {
@@ -1191,15 +1188,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;
+               }
+
+             fixup_debug_insns (reg, reg_sum, insn, lowest_ruid->insn);
 
              /* Delete the reg-reg addition.  */
              delete_insn (insn);
@@ -1210,8 +1213,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;
            }
        }
@@ -1253,14 +1254,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
@@ -1313,7 +1306,7 @@ reload_combine (void)
          if (! fixed_regs[r])
              reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
 
-      if (! INSN_P (insn))
+      if (! NONDEBUG_INSN_P (insn))
        continue;
 
       reload_combine_ruid++;
@@ -1520,6 +1513,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
@@ -1647,39 +1645,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_rtx_cost (pat, SET, &oldcst);
+      SET_SRC (pat) = tem;
+      get_full_rtx_cost (pat, SET, &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;
+               }
            }
        }
     }
@@ -1707,11 +1711,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_rtx_cost (pat, SET, &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
@@ -1730,22 +1741,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_rtx_cost (pat, SET, &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;
 
@@ -1855,7 +1869,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);
@@ -1881,18 +1895,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_rtx_cost (set, SET, &oldcst);
+                         SET_SRC (set) = tem;
+                         get_full_rtx_cost (tem, SET, &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);
@@ -2106,15 +2128,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);