OSDN Git Service

* config/avr/avr-protos.h (avr_output_addr_vec_elt): Prototype.
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index ee2fa48..86d80c1 100644 (file)
@@ -647,7 +647,7 @@ get_secondary_mem (x, mode, opnum, type)
 void
 clear_secondary_mem ()
 {
-  bzero ((char *) secondary_memlocs, sizeof secondary_memlocs);
+  memset ((char *) secondary_memlocs, 0, sizeof secondary_memlocs);
 }
 #endif /* SECONDARY_MEMORY_NEEDED */
 \f
@@ -946,7 +946,8 @@ push_reload (in, out, inloc, outloc, class,
   if (in != 0 && GET_CODE (in) == SUBREG
       && (SUBREG_WORD (in) == 0 || strict_low)
 #ifdef CLASS_CANNOT_CHANGE_MODE
-      && class != CLASS_CANNOT_CHANGE_MODE
+      && (class != CLASS_CANNOT_CHANGE_MODE
+         || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode))
 #endif
       && (CONSTANT_P (SUBREG_REG (in))
          || GET_CODE (SUBREG_REG (in)) == PLUS
@@ -1051,7 +1052,9 @@ push_reload (in, out, inloc, outloc, class,
   if (out != 0 && GET_CODE (out) == SUBREG
       && (SUBREG_WORD (out) == 0 || strict_low)
 #ifdef CLASS_CANNOT_CHANGE_MODE
-      && class != CLASS_CANNOT_CHANGE_MODE
+      && (class != CLASS_CANNOT_CHANGE_MODE
+         || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
+                                          outmode))
 #endif
       && (CONSTANT_P (SUBREG_REG (out))
          || strict_low
@@ -1555,7 +1558,7 @@ remove_address_replacements (in_rtx)
   char reload_flags[MAX_RELOADS];
   int something_changed = 0;
 
-  bzero (reload_flags, sizeof reload_flags);
+  memset (reload_flags, 0, sizeof reload_flags);
   for (i = 0, j = 0; i < n_replacements; i++)
     {
       if (loc_mentioned_in_p (replacements[i].where, in_rtx))
@@ -2396,6 +2399,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   int no_input_reloads = 0, no_output_reloads = 0;
   int n_alternatives;
   int this_alternative[MAX_RECOG_OPERANDS];
+  char this_alternative_match_win[MAX_RECOG_OPERANDS];
   char this_alternative_win[MAX_RECOG_OPERANDS];
   char this_alternative_offmemok[MAX_RECOG_OPERANDS];
   char this_alternative_earlyclobber[MAX_RECOG_OPERANDS];
@@ -2407,6 +2411,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   int operand_reloadnum[MAX_RECOG_OPERANDS];
   int goal_alternative_matches[MAX_RECOG_OPERANDS];
   int goal_alternative_matched[MAX_RECOG_OPERANDS];
+  char goal_alternative_match_win[MAX_RECOG_OPERANDS];
   char goal_alternative_win[MAX_RECOG_OPERANDS];
   char goal_alternative_offmemok[MAX_RECOG_OPERANDS];
   char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS];
@@ -2446,7 +2451,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   /* The eliminated forms of any secondary memory locations are per-insn, so
      clear them out here.  */
 
-  bzero ((char *) secondary_memlocs_elim, sizeof secondary_memlocs_elim);
+  memset ((char *) secondary_memlocs_elim, 0, sizeof secondary_memlocs_elim);
 #endif
 
   /* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it
@@ -2738,6 +2743,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        {
          register char *p = constraints[i];
          register int win = 0;
+         int did_match = 0;
          /* 0 => this operand can be reloaded somehow for this alternative */
          int badop = 1;
          /* 0 => this operand can be reloaded if the alternative allows regs.  */
@@ -2836,6 +2842,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
          this_alternative[i] = (int) NO_REGS;
          this_alternative_win[i] = 0;
+         this_alternative_match_win[i] = 0;
          this_alternative_offmemok[i] = 0;
          this_alternative_earlyclobber[i] = 0;
          this_alternative_matches[i] = -1;
@@ -2914,7 +2921,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                        && ! this_alternative_win[c])
                      bad = 1;
 
-                   win = this_alternative_win[c];
+                   did_match = this_alternative_win[c];
                  }
                else
                  {
@@ -2950,12 +2957,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                   operand also had to match the same thing as this
                   operand, we don't know how to do that.  So reject this
                   alternative.  */
-               if (! win || force_reload)
+               if (! did_match || force_reload)
                  for (j = 0; j < i; j++)
                    if (this_alternative_matches[j]
                        == this_alternative_matches[i])
                      badop = 1;
-
                break;
 
              case 'p':
@@ -3172,6 +3178,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          this_alternative_earlyclobber[i] = earlyclobber;
          if (win && ! force_reload)
            this_alternative_win[i] = 1;
+         else if (did_match && ! force_reload)
+           this_alternative_match_win[i] = 1;
          else
            {
              int const_to_mem = 0;
@@ -3273,7 +3281,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
             Don't do this if the preferred class has only one register
             because we might otherwise exhaust the class.  */
 
-         if (! win && this_alternative[i] != (int) NO_REGS
+         if (! win && ! did_match
+             && this_alternative[i] != (int) NO_REGS
              && GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
              && reg_class_size[(int) preferred_class[i]] > 1)
            {
@@ -3299,7 +3308,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
       for (i = 0; i < noperands; i++)
        if (this_alternative_earlyclobber[i]
-           && this_alternative_win[i])
+           && (this_alternative_win[i] || this_alternative_match_win[i]))
          {
            struct decomposition early_data;
 
@@ -3342,6 +3351,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                    {
                      losers++;
                      this_alternative_win[j] = 0;
+                     this_alternative_match_win[j] = 0;
                    }
                  else
                    break;
@@ -3352,11 +3362,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              {
                losers++;
                this_alternative_win[i] = 0;
+               this_alternative_match_win[j] = 0;
                for (j = 0; j < noperands; j++)
                  if (this_alternative_matches[j] == i
-                     && this_alternative_win[j])
+                     && this_alternative_match_win[j])
                    {
                      this_alternative_win[j] = 0;
+                     this_alternative_match_win[j] = 0;
                      losers++;
                    }
              }
@@ -3375,7 +3387,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            }
          for (i = 0; i < noperands; i++)
            {
-             goal_alternative_win[i] = 1;
+             goal_alternative_win[i] = this_alternative_win[i];
+             goal_alternative_match_win[i] = this_alternative_match_win[i];
              goal_alternative[i] = this_alternative[i];
              goal_alternative_offmemok[i] = this_alternative_offmemok[i];
              goal_alternative_matches[i] = this_alternative_matches[i];
@@ -3403,6 +3416,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            {
              goal_alternative[i] = this_alternative[i];
              goal_alternative_win[i] = this_alternative_win[i];
+             goal_alternative_match_win[i] = this_alternative_match_win[i];
              goal_alternative_offmemok[i] = this_alternative_offmemok[i];
              goal_alternative_matches[i] = this_alternative_matches[i];
              goal_alternative_earlyclobber[i]
@@ -3484,12 +3498,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
   for (i = 0; i < noperands; i++)
     goal_alternative_matched[i] = -1;
-
   for (i = 0; i < noperands; i++)
     if (! goal_alternative_win[i]
        && goal_alternative_matches[i] >= 0)
       goal_alternative_matched[goal_alternative_matches[i]] = i;
 
+  for (i = 0; i < noperands; i++)
+    goal_alternative_win[i] |= goal_alternative_match_win[i];
+
   /* If the best alternative is with operands 1 and 2 swapped,
      consider them swapped before reporting the reloads.  Update the
      operand numbers of any reloads already pushed.  */
@@ -4519,7 +4536,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
 
       else if (regno < FIRST_PSEUDO_REGISTER
               && REGNO_MODE_OK_FOR_BASE_P (regno, mode)
-              && ! regno_clobbered_p (regno, this_insn))
+              && ! regno_clobbered_p (regno, this_insn, mode, 0))
        return 0;
 
       /* If we do not have one of the cases above, we must do the reload.  */
@@ -5138,7 +5155,9 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
 
        if (REG_P (XEXP (op1, 0)))
          {
-           register int regno = REGNO (XEXP (op1, 0));
+           rtx link;
+           int regno = REGNO (XEXP (op1, 0));
+           int reloadnum;
 
            /* A register that is incremented cannot be constant!  */
            if (regno >= FIRST_PSEUDO_REGISTER
@@ -5161,15 +5180,17 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
                       write back the value after reading it, hence we actually
                       need two registers.  */
                    find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
-                                         &XEXP (tem, 0), opnum, type,
+                                         &XEXP (tem, 0), opnum,
+                                         RELOAD_OTHER,
                                          ind_levels, insn);
 
                    /* Then reload the memory location into a base
                       register.  */
-                   push_reload (tem, tem, &XEXP (x, 0), &XEXP (op1, 0),
-                                BASE_REG_CLASS, GET_MODE (x), GET_MODE (x),
-                                0, 0, opnum, RELOAD_OTHER);
-                   break;
+                   reloadnum = push_reload (tem, tem, &XEXP (x, 0),
+                                            &XEXP (op1, 0), BASE_REG_CLASS,
+                                            GET_MODE (x), GET_MODE (x), 0,
+                                            0, opnum, RELOAD_OTHER);
+                   goto reg_inc;
                  }
              }
 
@@ -5179,12 +5200,19 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
            /* We require a base register here...  */
            if (!REGNO_MODE_OK_FOR_BASE_P (regno, GET_MODE (x)))
              {
-               push_reload (XEXP (op1, 0), XEXP (x, 0),
-                            &XEXP (op1, 0), &XEXP (x, 0),
-                            BASE_REG_CLASS,
-                            GET_MODE (x), GET_MODE (x), 0, 0,
-                            opnum, RELOAD_OTHER);
+               reloadnum = push_reload (XEXP (op1, 0), XEXP (x, 0),
+                                        &XEXP (op1, 0), &XEXP (x, 0),
+                                        BASE_REG_CLASS,
+                                        GET_MODE (x), GET_MODE (x), 0, 0,
+                                        opnum, RELOAD_OTHER);
              }
+
+           /* Update the REG_INC notes.  */
+         reg_inc:
+           for (link = REG_NOTES (this_insn); link; link = XEXP (link, 1))
+             if (REG_NOTE_KIND (link) == REG_INC
+                 && REGNO (XEXP (link, 0)) == regno)
+               push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
          }
        else
          abort ();
@@ -5273,21 +5301,18 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
                        && ((*insn_data[icode].operand[1].predicate)
                            (equiv, Pmode))))
                {
-                 loc = &XEXP (x, 0);
+                 /* We use the original pseudo for loc, so that
+                    emit_reload_insns() knows which pseudo this
+                    reload refers to and updates the pseudo rtx, not
+                    its equivalent memory location, as well as the
+                    corresponding entry in reg_last_reload_reg.  */
+                 loc = &XEXP (x_orig, 0);
                  x = XEXP (x, 0);
                  reloadnum
                    = push_reload (x, x, loc, loc,
                                   (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
                                   GET_MODE (x), GET_MODE (x), 0, 0,
                                   opnum, RELOAD_OTHER);
-
-                 /* If we created a new MEM based on reg_equiv_mem[REGNO], then
-                    LOC above is part of the new MEM, not the MEM in INSN.
-
-                    We must also replace the address of the MEM in INSN.  */
-                 if (&XEXP (x_orig, 0) != loc)
-                   push_replacement (&XEXP (x_orig, 0), reloadnum, VOIDmode);
-
                }
              else
                {
@@ -5427,7 +5452,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
           in this insn, reload it into some other register to be safe.
           The CLOBBER is supposed to make the register unavailable
           from before this insn to after it.  */
-       if (regno_clobbered_p (regno, this_insn))
+       if (regno_clobbered_p (regno, this_insn, GET_MODE (x), 0))
          {
            push_reload (x, NULL_RTX, loc, NULL_PTR,
                         (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
@@ -5525,18 +5550,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
     {
       rtx tem;
 
-      /* If this is a CONST_INT, it could have been created by a
-        plus_constant call in eliminate_regs, which means it may be
-        on the reload_obstack.  reload_obstack will be freed later, so
-        we can't allow such RTL to be put in the constant pool.  There
-        is code in force_const_mem to check for this case, but it doesn't
-        work because we have already popped off the reload_obstack, so
-        rtl_obstack == saveable_obstack is true at this point.  */
-      if (GET_CODE (x) == CONST_INT)
-       tem = x = force_const_mem (mode, GEN_INT (INTVAL (x)));
-      else
-       tem = x = force_const_mem (mode, x);
-
+      tem = x = force_const_mem (mode, x);
       find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
                            opnum, type, ind_levels, 0);
     }
@@ -5548,12 +5562,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
     {
       rtx tem;
 
-      /* See comment above.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
-       tem = force_const_mem (GET_MODE (x), GEN_INT (INTVAL (XEXP (x, 1))));
-      else
-       tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
-
+      tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
       x = gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), tem);
       find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
                            opnum, type, ind_levels, 0);
@@ -6187,16 +6196,29 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
                      && (valtry
                          = operand_subword (SET_DEST (pat), 1, 0, VOIDmode))
                      && (valueno = true_regnum (valtry)) >= 0)))
-           if (other >= 0
-               ? valueno == other
-               : ((unsigned) valueno < FIRST_PSEUDO_REGISTER
-                  && TEST_HARD_REG_BIT (reg_class_contents[(int) class],
-                                        valueno)))
-             {
-               value = valtry;
-               where = p;
-               break;
-             }
+           {
+             if (other >= 0)
+               {
+                 if (valueno != other)
+                   continue;
+               }
+             else if ((unsigned) valueno >= FIRST_PSEUDO_REGISTER)
+               continue;
+             else
+               {
+                 int i;
+
+                 for (i = HARD_REGNO_NREGS (valueno, mode) - 1; i >= 0; i--)
+                   if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+                                            valueno + i))
+                     break;
+                 if (i >= 0)
+                   continue;
+               }
+             value = valtry;
+             where = p;
+             break;
+           }
        }
     }
 
@@ -6541,16 +6563,27 @@ find_inc_amount (x, inced)
   return 0;
 }
 \f
-/* Return 1 if register REGNO is the subject of a clobber in insn INSN.  */
+/* Return 1 if register REGNO is the subject of a clobber in insn INSN.
+   If SETS is nonzero, also consider SETs.  */
 
 int
-regno_clobbered_p (regno, insn)
+regno_clobbered_p (regno, insn, mode, sets)
      unsigned int regno;
      rtx insn;
+     enum machine_mode mode;
+     int sets;
 {
-  if (GET_CODE (PATTERN (insn)) == CLOBBER
+  int nregs = HARD_REGNO_NREGS (regno, mode);
+  int endregno = regno + nregs;
+
+  if ((GET_CODE (PATTERN (insn)) == CLOBBER
+       || (sets && GET_CODE (PATTERN (insn)) == SET))
       && GET_CODE (XEXP (PATTERN (insn), 0)) == REG)
-    return REGNO (XEXP (PATTERN (insn), 0)) == regno;
+    {
+      int test = REGNO (XEXP (PATTERN (insn), 0));
+
+      return test >= regno && test < endregno;
+    }
 
   if (GET_CODE (PATTERN (insn)) == PARALLEL)
     {
@@ -6559,9 +6592,15 @@ regno_clobbered_p (regno, insn)
       for (; i >= 0; i--)
        {
          rtx elt = XVECEXP (PATTERN (insn), 0, i);
-         if (GET_CODE (elt) == CLOBBER && GET_CODE (XEXP (elt, 0)) == REG
-             && REGNO (XEXP (elt, 0)) == regno)
-           return 1;
+         if ((GET_CODE (elt) == CLOBBER
+              || (sets && GET_CODE (PATTERN (insn)) == SET))
+             && GET_CODE (XEXP (elt, 0)) == REG)
+           {
+             int test = REGNO (XEXP (elt, 0));
+             
+             if (test >= regno && test < endregno)
+               return 1;
+           }
        }
     }
 
@@ -6626,7 +6665,7 @@ debug_reload_to_stream (f)
        fprintf (f, ", optional");
 
       if (rld[r].nongroup)
-       fprintf (stderr, ", nongroup");
+       fprintf (f, ", nongroup");
 
       if (rld[r].inc != 0)
        fprintf (f, ", inc by %d", rld[r].inc);
@@ -6670,13 +6709,13 @@ debug_reload_to_stream (f)
       prefix = "\n\t";
       if (rld[r].secondary_in_icode != CODE_FOR_nothing)
        {
-         fprintf (stderr, "%ssecondary_in_icode = %s", prefix,
+         fprintf (f, "%ssecondary_in_icode = %s", prefix,
                   insn_data[rld[r].secondary_in_icode].name);
          prefix = ", ";
        }
 
       if (rld[r].secondary_out_icode != CODE_FOR_nothing)
-       fprintf (stderr, "%ssecondary_out_icode = %s", prefix,
+       fprintf (f, "%ssecondary_out_icode = %s", prefix,
                 insn_data[rld[r].secondary_out_icode].name);
 
       fprintf (f, "\n");