OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index 5c0aabe..5a82d99 100644 (file)
@@ -260,6 +260,7 @@ static int alternative_allows_memconst PARAMS ((const char *, int));
 static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int,
                                         int, rtx, int *));
 static rtx make_memloc         PARAMS ((rtx, int));
+static int maybe_memory_address_p PARAMS ((enum machine_mode, rtx, rtx *));
 static int find_reloads_address        PARAMS ((enum machine_mode, rtx *, rtx, rtx *,
                                       int, enum reload_type, int, rtx));
 static rtx subst_reg_equivs    PARAMS ((rtx, rtx));
@@ -975,9 +976,7 @@ push_reload (in, out, inloc, outloc, class,
   if (in != 0 && GET_CODE (in) == SUBREG
       && (subreg_lowpart_p (in) || strict_low)
 #ifdef CANNOT_CHANGE_MODE_CLASS
-      && !reg_classes_intersect_p 
-          (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)),
-                                            inmode))
+      && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, class)
 #endif
       && (CONSTANT_P (SUBREG_REG (in))
          || GET_CODE (SUBREG_REG (in)) == PLUS
@@ -1087,9 +1086,7 @@ push_reload (in, out, inloc, outloc, class,
   if (out != 0 && GET_CODE (out) == SUBREG
       && (subreg_lowpart_p (out) || strict_low)
 #ifdef CANNOT_CHANGE_MODE_CLASS
-      && !reg_classes_intersect_p 
-           (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)),
-                                             outmode))
+      && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, class)
 #endif
       && (CONSTANT_P (SUBREG_REG (out))
          || strict_low
@@ -2140,10 +2137,10 @@ operands_match_p (x, y)
         (reg:SI 1) will be considered the same register.  */
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
          && i < FIRST_PSEUDO_REGISTER)
-       i += (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD) - 1;
+       i += HARD_REGNO_NREGS (i, GET_MODE (x)) - 1;
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD
          && j < FIRST_PSEUDO_REGISTER)
-       j += (GET_MODE_SIZE (GET_MODE (y)) / UNITS_PER_WORD) - 1;
+       j += HARD_REGNO_NREGS (j, GET_MODE (y)) - 1;
 
       return i == j;
     }
@@ -2479,6 +2476,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   char pref_or_nothing[MAX_RECOG_OPERANDS];
   /* Nonzero for a MEM operand whose entire address needs a reload.  */
   int address_reloaded[MAX_RECOG_OPERANDS];
+  /* Nonzero for an address operand that needs to be completely reloaded.  */
+  int address_operand_reloaded[MAX_RECOG_OPERANDS];
   /* Value of enum reload_type to use for operand.  */
   enum reload_type operand_type[MAX_RECOG_OPERANDS];
   /* Value of enum reload_type to use within address of operand.  */
@@ -2658,6 +2657,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       RTX_CODE code = GET_CODE (recog_data.operand[i]);
 
       address_reloaded[i] = 0;
+      address_operand_reloaded[i] = 0;
       operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT
                         : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT
                         : RELOAD_OTHER);
@@ -2672,10 +2672,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       else if (constraints[i][0] == 'p'
               || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
        {
-         find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
-                               recog_data.operand[i],
-                               recog_data.operand_loc[i],
-                               i, operand_type[i], ind_levels, insn);
+         address_operand_reloaded[i]
+           = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
+                                   recog_data.operand[i],
+                                   recog_data.operand_loc[i],
+                                   i, operand_type[i], ind_levels, insn);
 
          /* If we now have a simple operand where we used to have a
             PLUS or MULT, re-recognize and try again.  */
@@ -2692,6 +2693,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
          recog_data.operand[i] = *recog_data.operand_loc[i];
          substed_operand[i] = recog_data.operand[i];
+
+         /* Address operands are reloaded in their existing mode,
+            no matter what is specified in the machine description.  */
+         operand_mode[i] = GET_MODE (recog_data.operand[i]);
        }
       else if (code == MEM)
        {
@@ -2875,6 +2880,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              if (GET_CODE (SUBREG_REG (operand)) == REG
                  && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
                {
+                 if (!subreg_offset_representable_p
+                       (REGNO (SUBREG_REG (operand)),
+                        GET_MODE (SUBREG_REG (operand)),
+                        SUBREG_BYTE (operand),
+                        GET_MODE (operand)))
+                    force_reload = 1;
                  offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
                                                 GET_MODE (SUBREG_REG (operand)),
                                                 SUBREG_BYTE (operand),
@@ -2930,26 +2941,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                          )
 #endif
                      )
-                 /* This following hunk of code should no longer be
-                    needed at all with SUBREG_BYTE.  If you need this
-                    code back, please explain to me why so I can
-                    fix the real problem.  -DaveM */
-#if 0
-                 /* Subreg of a hard reg which can't handle the subreg's mode
-                    or which would handle that mode in the wrong number of
-                    registers for subregging to work.  */
-                 || (GET_CODE (operand) == REG
-                     && REGNO (operand) < FIRST_PSEUDO_REGISTER
-                     && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
-                          && (GET_MODE_SIZE (GET_MODE (operand))
-                              > UNITS_PER_WORD)
-                          && ((GET_MODE_SIZE (GET_MODE (operand))
-                               / UNITS_PER_WORD)
-                              != HARD_REGNO_NREGS (REGNO (operand),
-                                                   GET_MODE (operand))))
-                         || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
-                                                  operand_mode[i])))
-#endif
                  )
                force_reload = 1;
            }
@@ -3305,10 +3296,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                           the address into a base register.  */
                        this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode);
                        badop = 0;
-
-                       /* Address constraints are reloaded in Pmode, no matter
-                          what mode is given in the machine description.  */
-                       operand_mode[i] = Pmode;
                        break;
                      }
 
@@ -3881,6 +3868,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       }
     else if (goal_alternative_matched[i] < 0
             && goal_alternative_matches[i] < 0
+            && !address_operand_reloaded[i]
             && optimize)
       {
        /* For each non-matching operand that's a MEM or a pseudo-register
@@ -4358,7 +4346,17 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        if (regno < FIRST_PSEUDO_REGISTER
            && TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno)
            && HARD_REGNO_MODE_OK (regno, rld[i].mode))
-         rld[i].reg_rtx = dest;
+         {
+           int nr = HARD_REGNO_NREGS (regno, rld[i].mode);
+           int ok = 1, nri;
+
+           for (nri = 1; nri < nr; nri ++)
+             if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno + nri))
+               ok = 0;
+
+           if (ok)
+             rld[i].reg_rtx = dest;
+         }
       }
 
   return retval;
@@ -4587,6 +4585,27 @@ make_memloc (ad, regno)
   return tem;
 }
 
+/* Returns true if AD could be turned into a valid memory reference
+   to mode MODE by reloading the part pointed to by PART into a 
+   register.  */
+
+static int
+maybe_memory_address_p (mode, ad, part)
+     enum machine_mode mode;
+     rtx ad;
+     rtx *part;
+{
+  int retv;
+  rtx tem = *part;
+  rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ());
+
+  *part = reg;
+  retv = memory_address_p (mode, ad);
+  *part = tem;
+
+  return retv;
+}
+
 /* Record all reloads needed for handling memory address AD
    which appears in *LOC in a memory reference to mode MODE
    which itself is found in location  *MEMREFLOC.
@@ -4867,26 +4886,24 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
      that the index needs a reload and find_reloads_address_1 will take care
      of it.
 
-     If we decide to do something here, it must be that
-     `double_reg_address_ok' is true and that this address rtl was made by
-     eliminate_regs.  We generate a reload of the fp/sp/ap + constant and
+     Handle all base registers here, not just fp/ap/sp, because on some
+     targets (namely Sparc) we can also get invalid addresses from preventive
+     subreg big-endian corrections made by find_reloads_toplev.
+
+     If we decide to do something, it must be that `double_reg_address_ok'
+     is true.  We generate a reload of the base register + constant and
      rework the sum so that the reload register will be added to the index.
      This is safe because we know the address isn't shared.
 
-     We check for fp/ap/sp as both the first and second operand of the
-     innermost PLUS.  */
+     We check for the base register as both the first and second operand of
+     the innermost PLUS.  */
 
   else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
           && GET_CODE (XEXP (ad, 0)) == PLUS
-          && (XEXP (XEXP (ad, 0), 0) == frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 0) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
-#endif
-              || XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
-          && ! memory_address_p (mode, ad))
+          && GET_CODE (XEXP (XEXP (ad, 0), 0)) == REG
+          && REGNO (XEXP (XEXP (ad, 0), 0)) < FIRST_PSEUDO_REGISTER
+          && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 0), mode)
+          && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1)))
     {
       *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
                                plus_constant (XEXP (XEXP (ad, 0), 0),
@@ -4903,15 +4920,10 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
 
   else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
           && GET_CODE (XEXP (ad, 0)) == PLUS
-          && (XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 1) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
-#endif
-              || XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
-          && ! memory_address_p (mode, ad))
+          && GET_CODE (XEXP (XEXP (ad, 0), 1)) == REG
+          && REGNO (XEXP (XEXP (ad, 0), 1)) < FIRST_PSEUDO_REGISTER
+          && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 1), mode)
+          && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0)))
     {
       *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
                                XEXP (XEXP (ad, 0), 0),
@@ -5176,7 +5188,7 @@ update_auto_inc_notes (insn, regno, reloadnum)
 
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == REG_INC
-        && REGNO (XEXP (link, 0)) == regno)
+        && (int) REGNO (XEXP (link, 0)) == regno)
       push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
 #endif
 }
@@ -5256,6 +5268,19 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
                                                       SUBREG_BYTE (orig_op1),
                                                       GET_MODE (orig_op1))));
          }
+       /* Plus in the index register may be created only as a result of
+          register remateralization for expresion like &localvar*4.  Reload it.
+          It may be possible to combine the displacement on the outer level,
+          but it is probably not worthwhile to do so.  */
+       if (context)
+         {
+           find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
+                                 opnum, ADDR_TYPE (type), ind_levels, insn);
+           push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
+                        (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+                        GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+           return 1;
+         }
 
        if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
            || code0 == ZERO_EXTEND || code1 == MEM)
@@ -5931,7 +5956,7 @@ subst_reloads (insn)
             do the wrong thing if RELOADREG is multi-word.  RELOADREG
             will always be a REG here.  */
          if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
-           reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
+           reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode);
 
          /* If we are putting this into a SUBREG and RELOADREG is a
             SUBREG, we would be making nested SUBREGs, so we have to fix
@@ -6911,6 +6936,26 @@ regno_clobbered_p (regno, insn, mode, sets)
   return 0;
 }
 
+/* Find the low part, with mode MODE, of a hard regno RELOADREG.  */
+rtx
+reload_adjust_reg_for_mode (reloadreg, mode)
+     rtx reloadreg;
+     enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (reloadreg) == mode)
+    return reloadreg;
+
+  regno = REGNO (reloadreg);
+
+  if (WORDS_BIG_ENDIAN)
+    regno += HARD_REGNO_NREGS (regno, GET_MODE (reloadreg))
+      - HARD_REGNO_NREGS (regno, mode);
+
+  return gen_rtx_REG (mode, regno);
+}
+
 static const char *const reload_when_needed_name[] =
 {
   "RELOAD_FOR_INPUT",