Fix for g++ failure reported by Brendan.
[platform/upstream/gcc.git] / gcc / reload.c
index 6431f15..a97357f 100644 (file)
@@ -2031,7 +2031,7 @@ operands_match_p (x, y)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      int val;
+      int val, j;
       switch (fmt[i])
        {
        case 'w':
@@ -2057,6 +2057,19 @@ operands_match_p (x, y)
        case '0':
          break;
 
+       case 'E':
+         if (XVECLEN (x, i) != XVECLEN (y, i))
+           return 0;
+         for (j = XVECLEN (x, i) - 1; j >= 0; --j)
+           {
+             val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j));
+             if (val == 0)
+               return 0;
+             if (val == 2)
+               success_2 = 1;
+           }
+         break;
+
          /* It is believed that rtx's at this level will never
             contain anything but integers and other rtx's,
             except for within LABEL_REFs and SYMBOL_REFs.  */
@@ -2660,7 +2673,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            substed_operand[i] = recog_operand[i]
              = reg_equiv_mem[regno];
 #endif
-         if (reg_equiv_address[regno] != 0)
+         if (reg_equiv_address[regno] != 0
+             && (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
            {
              /* If reg_equiv_address is not a constant address, copy it,
                 since it may be shared.  */
@@ -3222,14 +3236,20 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  && this_alternative_matches[i] < 0)
                bad = 1;
 
+#if 0
              /* If this is a pseudo-register that is set in the previous
                 insns, there's a good chance that it will already be in a
                 spill register and we can use that spill register.  So
-                make this case cheaper.  */
+                make this case cheaper. 
+
+                Disabled for egcs.  egcs has better inheritance code and
+                this change causes problems with the improved reload
+                inheritance code.  */
              if (GET_CODE (operand) == REG
                  && REGNO (operand) >= FIRST_PSEUDO_REGISTER
                  && REGNO (operand) == last_output_reload_regno)
                reject--;
+#endif
 
              /* If this is a constant that is reloaded into the desired
                 class by copying it to memory first, count that as another
@@ -3994,17 +4014,82 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
      actually fail are extremely rare, so it turns out to be better to fix
      the problem here by not generating cases that choose_reload_regs will
      fail for.  */
-   
+  /* There is a similar problem with RELOAD_FOR_INPUT_ADDRESS /
+     RELOAD_FOR_OUTPUT_ADDRESS when there is more than one of a kind for
+     a single operand.
+     We can reduce the register pressure by exploiting that a
+     RELOAD_FOR_X_ADDR_ADDR that precedes all RELOAD_FOR_X_ADDRESS reloads
+     does not conflict with any of them.  */
   {
-    int op_addr_reloads = 0;
-    for (i = 0; i < n_reloads; i++)
-      if (reload_when_needed[i] == RELOAD_FOR_OPERAND_ADDRESS)
-       op_addr_reloads++;
+    int first_op_addr_num = -2;
+    int first_inpaddr_num[MAX_RECOG_OPERANDS];
+    int first_outpaddr_num[MAX_RECOG_OPERANDS];
+    int need_change= 0;
+    /* We use last_op_addr_reload and the contents of the above arrays
+       first as flags - -2 means no instance encountered, -1 means exactly
+       one instance encountered.
+       If more than one instance has been encountered, we store the reload
+       number of the first reload of the kind in question; reload numbers
+       are known to be non-negative.  */
+    for (i = 0; i < noperands; i++)
+      first_inpaddr_num[i] = first_outpaddr_num[i] = -2;
+    for (i = n_reloads - 1; i >= 0; i--)
+      {
+       switch (reload_when_needed[i])
+         {
+         case RELOAD_FOR_OPERAND_ADDRESS:
+           if (! ++first_op_addr_num)
+             {
+               first_op_addr_num= i;
+               need_change = 1;
+             }
+           break;
+         case RELOAD_FOR_INPUT_ADDRESS:
+           if (! ++first_inpaddr_num[reload_opnum[i]])
+             {
+               first_inpaddr_num[reload_opnum[i]] = i;
+               need_change = 1;
+             }
+           break;
+         case RELOAD_FOR_OUTPUT_ADDRESS:
+           if (! ++first_outpaddr_num[reload_opnum[i]])
+             {
+               first_outpaddr_num[reload_opnum[i]] = i;
+               need_change = 1;
+             }
+           break;
+         default:
+           break;
+         }
+      }
 
-    if (op_addr_reloads > 1)
-      for (i = 0; i < n_reloads; i++)
-       if (reload_when_needed[i] == RELOAD_FOR_OPADDR_ADDR)
-         reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+    if (need_change)
+      {
+       for (i = 0; i < n_reloads; i++)
+         {
+           int first_num, type;
+
+           switch (reload_when_needed[i])
+             {
+             case RELOAD_FOR_OPADDR_ADDR:
+               first_num = first_op_addr_num;
+               type = RELOAD_FOR_OPERAND_ADDRESS;
+               break;
+             case RELOAD_FOR_INPADDR_ADDRESS:
+               first_num = first_inpaddr_num[reload_opnum[i]];
+               type = RELOAD_FOR_INPUT_ADDRESS;
+               break;
+             case RELOAD_FOR_OUTADDR_ADDRESS:
+               first_num = first_outpaddr_num[reload_opnum[i]];
+               type = RELOAD_FOR_OUTPUT_ADDRESS;
+               break;
+             default:
+               continue;
+             }
+           if (i > first_num)
+             reload_when_needed[i] = type;
+         }
+      }
   }
 
   /* See if we have any reloads that are now allowed to be merged
@@ -5751,7 +5836,14 @@ reg_overlap_mentioned_for_reload_p (x, in)
 {
   int regno, endregno;
 
-  if (GET_CODE (x) == SUBREG)
+  /* Overly conservative.  */
+  if (GET_CODE (x) == STRICT_LOW_PART)
+    x = XEXP (x, 0);
+
+  /* If either argument is a constant, then modifying X can not affect IN.  */
+  if (CONSTANT_P (x) || CONSTANT_P (in))
+    return 0;
+  else if (GET_CODE (x) == SUBREG)
     {
       regno = REGNO (SUBREG_REG (x));
       if (regno < FIRST_PSEUDO_REGISTER)
@@ -5773,8 +5865,6 @@ reg_overlap_mentioned_for_reload_p (x, in)
          abort ();
        }
     }
-  else if (CONSTANT_P (x))
-    return 0;
   else if (GET_CODE (x) == MEM)
     return refers_to_mem_for_reload_p (in);
   else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
@@ -5946,6 +6036,9 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
                   && (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0)
                  ||
                  (goal_const && rtx_equal_p (SET_SRC (pat), goal)
+                  /* When looking for stack pointer + const,
+                     make sure we don't use a stack adjust.  */
+                  && !reg_overlap_mentioned_for_reload_p (SET_DEST (pat), goal)
                   && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
                  || (goal_mem
                      && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0
@@ -6119,12 +6212,17 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
 
       if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
        {
+         pat = PATTERN (p);
+
+          /* Watch out for unspec_volatile, and volatile asms.  */
+          if (volatile_insn_p (pat))
+           return 0;
+
          /* If this insn P stores in either GOAL or VALUE, return 0.
             If GOAL is a memory ref and this insn writes memory, return 0.
             If GOAL is a memory ref and its address is not constant,
             and this insn P changes a register used in GOAL, return 0.  */
 
-         pat = PATTERN (p);
          if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
            {
              register rtx dest = SET_DEST (pat);
@@ -6149,6 +6247,8 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
                  if (goal_mem_addr_varies
                      && reg_overlap_mentioned_for_reload_p (dest, goal))
                    return 0;
+                 if (xregno == STACK_POINTER_REGNUM && need_stable_sp)
+                   return 0;
                }
              else if (goal_mem && GET_CODE (dest) == MEM
                       && ! push_operand (dest, GET_MODE (dest)))
@@ -6191,6 +6291,8 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
                              && reg_overlap_mentioned_for_reload_p (dest,
                                                                     goal))
                            return 0;
+                         if (xregno == STACK_POINTER_REGNUM && need_stable_sp)
+                           return 0;
                        }
                      else if (goal_mem && GET_CODE (dest) == MEM
                               && ! push_operand (dest, GET_MODE (dest)))