OSDN Git Service

* lex.c (lang_init_options): New function.
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index 9f2365f..1604a7b 100644 (file)
@@ -1,5 +1,5 @@
 /* Search an insn for pseudo regs that must be in hard regs and are not.
-   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -88,7 +88,7 @@ a register with any other reload.  */
 #define REG_OK_STRICT
 
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
 #include "rtl.h"
 #include "insn-config.h"
 #include "insn-codes.h"
@@ -100,6 +100,7 @@ a register with any other reload.  */
 #include "real.h"
 #include "output.h"
 #include "expr.h"
+#include "toplev.h"
 
 #ifndef REGISTER_MOVE_COST
 #define REGISTER_MOVE_COST(x, y) 2
@@ -128,6 +129,8 @@ a register with any other reload.  */
    reload_optional       char, nonzero for an optional reload.
                           Optional reloads are ignored unless the
                           value is already sitting in a register.
+   reload_nongroup       char, nonzero when a reload must use a register
+                          not already allocated to a group.
    reload_inc            int, positive amount to increment or decrement by if
                           reload_in is a PRE_DEC, PRE_INC, POST_DEC, POST_INC.
                           Ignored otherwise (don't assume it is zero).
@@ -175,6 +178,7 @@ enum machine_mode reload_inmode[MAX_RELOADS];
 enum machine_mode reload_outmode[MAX_RELOADS];
 rtx reload_reg_rtx[MAX_RELOADS];
 char reload_optional[MAX_RELOADS];
+char reload_nongroup[MAX_RELOADS];
 int reload_inc[MAX_RELOADS];
 rtx reload_in_reg[MAX_RELOADS];
 char reload_nocombine[MAX_RELOADS];
@@ -306,9 +310,11 @@ static int output_reloadnum;
       ? RELOAD_FOR_OUTADDR_ADDRESS                     \
       : (type)))
 
+#ifdef HAVE_SECONDARY_RELOADS
 static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class,
                                        enum machine_mode, enum reload_type,
                                        enum insn_code *));
+#endif
 static enum reg_class find_valid_class PROTO((enum machine_mode, int));
 static int push_reload         PROTO((rtx, rtx, rtx *, rtx *, enum reg_class,
                                       enum machine_mode, enum machine_mode,
@@ -366,7 +372,6 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
   enum machine_mode t_mode = VOIDmode;
   enum insn_code t_icode = CODE_FOR_nothing;
   enum reload_type secondary_type;
-  int i;
   int s_reload, t_reload = -1;
 
   if (type == RELOAD_FOR_INPUT_ADDRESS
@@ -526,6 +531,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
          reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode;
          reload_reg_rtx[t_reload] = 0;
          reload_optional[t_reload] = optional;
+         reload_nongroup[t_reload] = 0;
          reload_inc[t_reload] = 0;
          /* Maybe we could combine these, but it seems too tricky.  */
          reload_nocombine[t_reload] = 1;
@@ -594,6 +600,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
       reload_outmode[s_reload] = ! in_p ? mode : VOIDmode;
       reload_reg_rtx[s_reload] = 0;
       reload_optional[s_reload] = optional;
+      reload_nongroup[s_reload] = 0;
       reload_inc[s_reload] = 0;
       /* Maybe we could combine these, but it seems too tricky.  */
       reload_nocombine[s_reload] = 1;
@@ -830,10 +837,10 @@ push_reload (in, out, inloc, outloc, class,
     {
       if (GET_CODE (XEXP (in, 0)) == POST_INC
          || GET_CODE (XEXP (in, 0)) == POST_DEC)
-       in = gen_rtx (MEM, GET_MODE (in), XEXP (XEXP (in, 0), 0));
+       in = gen_rtx_MEM (GET_MODE (in), XEXP (XEXP (in, 0), 0));
       if (GET_CODE (XEXP (in, 0)) == PRE_INC
          || GET_CODE (XEXP (in, 0)) == PRE_DEC)
-       out = gen_rtx (MEM, GET_MODE (out), XEXP (XEXP (out, 0), 0));
+       out = gen_rtx_MEM (GET_MODE (out), XEXP (XEXP (out, 0), 0));
     }
 
   /* If we are reloading a (SUBREG constant ...), really reload just the
@@ -886,6 +893,13 @@ push_reload (in, out, inloc, outloc, class,
                      && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
                      && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != NIL)
 #endif
+#ifdef WORD_REGISTER_OPERATIONS
+                 || ((GET_MODE_SIZE (inmode)
+                      < GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+                     && ((GET_MODE_SIZE (inmode) - 1) / UNITS_PER_WORD ==
+                         ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1)
+                          / UNITS_PER_WORD)))
+#endif
                  ))
          || (GET_CODE (SUBREG_REG (in)) == REG
              && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
@@ -923,7 +937,7 @@ push_reload (in, out, inloc, outloc, class,
       in_subreg_loc = inloc;
       inloc = &SUBREG_REG (in);
       in = *inloc;
-#ifndef LOAD_EXTEND_OP
+#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
       if (GET_CODE (in) == MEM)
        /* This is supposed to happen only for paradoxical subregs made by
           combine.c.  (SUBREG (MEM)) isn't supposed to occur other ways.  */
@@ -987,9 +1001,11 @@ push_reload (in, out, inloc, outloc, class,
              && ((GET_MODE_SIZE (outmode)
                   > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
 #ifdef WORD_REGISTER_OPERATIONS
-                 || ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD ==
-                     ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1)
-                      / UNITS_PER_WORD))
+                 || ((GET_MODE_SIZE (outmode)
+                      < GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+                     && ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD ==
+                         ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1)
+                          / UNITS_PER_WORD)))
 #endif
                  ))
          || (GET_CODE (SUBREG_REG (out)) == REG
@@ -1025,7 +1041,7 @@ push_reload (in, out, inloc, outloc, class,
       out_subreg_loc = outloc;
       outloc = &SUBREG_REG (out);
       out = *outloc; 
-#ifndef LOAD_EXTEND_OP
+#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
      if (GET_CODE (out) == MEM
          && GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
        abort ();
@@ -1078,16 +1094,16 @@ push_reload (in, out, inloc, outloc, class,
   if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG
       && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
       && ! dont_remove_subreg)
-    in = gen_rtx (REG, GET_MODE (in),
-                 REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
+    in = gen_rtx_REG (GET_MODE (in),
+                     REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
 
   /* Similarly for OUT.  */
   if (out != 0 && GET_CODE (out) == SUBREG
       && GET_CODE (SUBREG_REG (out)) == REG
       && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
       && ! dont_remove_subreg)
-    out = gen_rtx (REG, GET_MODE (out),
-                 REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
+    out = gen_rtx_REG (GET_MODE (out),
+                      REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
 
   /* Narrow down the class of register wanted if that is
      desirable on this machine for efficiency.  */
@@ -1261,6 +1277,7 @@ push_reload (in, out, inloc, outloc, class,
       reload_outmode[i] = outmode;
       reload_reg_rtx[i] = 0;
       reload_optional[i] = optional;
+      reload_nongroup[i] = 0;
       reload_inc[i] = 0;
       reload_nocombine[i] = 0;
       reload_in_reg[i] = inloc ? *inloc : 0;
@@ -1442,7 +1459,7 @@ push_reload (in, out, inloc, outloc, class,
            && TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno)
            && !fixed_regs[regno])
          {
-           reload_reg_rtx[i] = gen_rtx (REG, inmode, regno);
+           reload_reg_rtx[i] = gen_rtx_REG (inmode, regno);
            break;
          }
     }
@@ -1489,6 +1506,21 @@ transfer_replacements (to, from)
       replacements[i].what = to;
 }
 \f
+/* Remove all replacements in reload FROM.  */
+void
+remove_replacements (from)
+     int from;
+{
+  int i, j;
+
+  for (i = 0, j = 0; i < n_replacements; i++)
+    {
+      if (replacements[i].what == from)
+        continue;
+      replacements[j++] = replacements[i];
+    }
+}
+\f
 /* If there is only one output reload, and it is not for an earlyclobber
    operand, try to combine it with a (logically unrelated) input reload
    to reduce the number of reload registers needed.
@@ -1658,9 +1690,9 @@ combine_reloads ()
                            REGNO (XEXP (note, 0)))))))
        && ! fixed_regs[REGNO (XEXP (note, 0))])
       {
-       reload_reg_rtx[output_reload] = gen_rtx (REG,
-                                                reload_outmode[output_reload],
-                                                REGNO (XEXP (note, 0)));
+       reload_reg_rtx[output_reload]
+         = gen_rtx_REG (reload_outmode[output_reload],
+                        REGNO (XEXP (note, 0)));
        return;
       }
 }
@@ -1764,7 +1796,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
              if (GET_CODE (real_out) == REG)
                value = real_out;
              else
-               value = gen_rtx (REG, outmode, regno);
+               value = gen_rtx_REG (outmode, regno);
            }
        }
 
@@ -1818,7 +1850,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
              if (GET_CODE (real_in) == REG)
                value = real_in;
              else
-               value = gen_rtx (REG, inmode, regno);
+               value = gen_rtx_REG (inmode, regno);
            }
        }
     }
@@ -2111,28 +2143,28 @@ decompose (x)
        {
          if (GET_CODE (XEXP (offset, 0)) == CONST_INT)
            {
-             base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 1));
+             base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1));
              offset = XEXP (offset, 0);
            }
          else if (GET_CODE (XEXP (offset, 1)) == CONST_INT)
            {
-             base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 0));
+             base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 0));
              offset = XEXP (offset, 1);
            }
          else
            {
-             base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+             base = gen_rtx_PLUS (GET_MODE (base), base, offset);
              offset = const0_rtx;
            }
        }
       else if (GET_CODE (offset) != CONST_INT)
        {
-         base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+         base = gen_rtx_PLUS (GET_MODE (base), base, offset);
          offset = const0_rtx;
        }
 
       if (all_const && GET_CODE (base) == PLUS)
-       base = gen_rtx (CONST, GET_MODE (base), base);
+       base = gen_rtx_CONST (GET_MODE (base), base);
 
       if (GET_CODE (offset) != CONST_INT)
        abort ();
@@ -2305,6 +2337,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   int goal_alternative_swapped;
   int best;
   int commutative;
+  int changed;
   char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
   rtx substed_operand[MAX_RECOG_OPERANDS];
   rtx body = PATTERN (insn);
@@ -2398,7 +2431,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  {
                    error_for_asm (insn, "operand constraints differ in number of alternatives");
                    /* Avoid further trouble with this insn.  */
-                   PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+                   PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
                    n_reloads = 0;
                    return;
                  }
@@ -2451,7 +2484,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       /* Scan this operand's constraint to see if it is an output operand, 
         an in-out operand, is commutative, or should match another.  */
 
-      while (c = *p++)
+      while ((c = *p++))
        {
          if (c == '=')
            modified[i] = RELOAD_WRITE;
@@ -2567,11 +2600,29 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
        }
       else if (code == SUBREG)
-       substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
-         = find_reloads_toplev (recog_operand[i], i, address_type[i],
-                                ind_levels,
-                                set != 0
-                                && &SET_DEST (set) == recog_operand_loc[i]);
+       {
+         rtx reg = SUBREG_REG (recog_operand[i]);
+         rtx op
+           = find_reloads_toplev (recog_operand[i], i, address_type[i],
+                                  ind_levels,
+                                  set != 0
+                                  && &SET_DEST (set) == recog_operand_loc[i]);
+
+         /* If we made a MEM to load (a part of) the stackslot of a pseudo
+            that didn't get a hard register, emit a USE with a REG_EQUAL
+            note in front so that we might inherit a previous, possibly
+            wider reload.  */
+            
+         if (GET_CODE (op) == MEM
+             && GET_CODE (reg) == REG
+             && (GET_MODE_SIZE (GET_MODE (reg))
+                 >= GET_MODE_SIZE (GET_MODE (op))))
+            REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, reg), insn))
+              = gen_rtx_EXPR_LIST (REG_EQUAL,
+                                  reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
+
+         substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] = op;
+       }
       else if (code == PLUS || GET_RTX_CLASS (code) == '1')
        /* We can get a PLUS as an "operand" as a result of register
           elimination.  See eliminate_regs and gen_reload.  We handle
@@ -2590,8 +2641,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          register int regno = REGNO (recog_operand[i]);
          if (reg_equiv_constant[regno] != 0
              && (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
-           substed_operand[i] = recog_operand[i]
-             = reg_equiv_constant[regno];
+           {
+             /* Record the existing mode so that the check if constants are
+                allowed will work when operand_mode isn't specified. */
+
+             if (operand_mode[i] == VOIDmode)
+               operand_mode[i] = GET_MODE (recog_operand[i]);
+
+             substed_operand[i] = recog_operand[i]
+               = reg_equiv_constant[regno];
+           }
 #if 0 /* This might screw code in reload1.c to delete prior output-reload
         that feeds this insn.  */
          if (reg_equiv_mem[regno] != 0)
@@ -2611,19 +2670,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              if (rtx_varies_p (address))
                address = copy_rtx (address);
 
-             /* If this is an output operand, we must output a CLOBBER
-                after INSN so find_equiv_reg knows REGNO is being written. 
-                Mark this insn specially, do we can put our output reloads
-                after it.  */
-
-             if (modified[i] != RELOAD_READ)
-               PUT_MODE (emit_insn_after (gen_rtx (CLOBBER, VOIDmode,
-                                                   recog_operand[i]),
-                                          insn),
-                         DImode);
+             /* Emit a USE that shows what register is being used/modified.  */
+             REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
+                                                       recog_operand[i]),
+                                          insn))
+               = gen_rtx_EXPR_LIST (REG_EQUAL,
+                                    reg_equiv_memory_loc[regno],
+                                    NULL_RTX);
 
              *recog_operand_loc[i] = recog_operand[i]
-               = gen_rtx (MEM, GET_MODE (recog_operand[i]), address);
+               = gen_rtx_MEM (GET_MODE (recog_operand[i]), address);
              RTX_UNCHANGING_P (recog_operand[i])
                = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
              find_reloads_address (GET_MODE (recog_operand[i]),
@@ -2660,7 +2716,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
      or got the wrong kind of hard reg.  For this, we must consider
      all the operands together against the register constraints.  */
 
-  best = MAX_RECOG_OPERANDS + 300;
+  best = MAX_RECOG_OPERANDS * 2 + 600;
 
   swapped = 0;
   goal_alternative_swapped = 0;
@@ -2715,8 +2771,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          int earlyclobber = 0;
 
          /* If the predicate accepts a unary operator, it means that
-             we need to reload the operand.  */
-         if (GET_RTX_CLASS (GET_CODE (operand)) == '1')
+             we need to reload the operand, but do not do this for
+            match_operator and friends.  */
+         if (GET_RTX_CLASS (GET_CODE (operand)) == '1' && *p != 0)
            operand = XEXP (operand, 0);
 
          /* If the operand is a SUBREG, extract
@@ -2727,7 +2784,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            {
              offset += SUBREG_WORD (operand);
              operand = SUBREG_REG (operand);
-             /* Force reload if this is a constant or PLUS or if there may may
+             /* Force reload if this is a constant or PLUS or if there may
                 be a problem accessing OPERAND in the outer mode.  */
              if (CONSTANT_P (operand)
                  || GET_CODE (operand) == PLUS
@@ -2745,10 +2802,20 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                     register access.  If the data is, in fact, in memory we
                     must always load using the size assumed to be in the
                     register and let the insn do the different-sized 
-                    accesses.  */
+                    accesses.
+
+                    This is doubly true if WORD_REGISTER_OPERATIONS.  In 
+                    this case eliminate_regs has left non-paradoxical
+                    subregs for push_reloads to see.  Make sure it does
+                    by forcing the reload.
+
+                    ??? When is it right at this stage to have a subreg
+                    of a mem that is _not_ to be handled specialy?  IMO
+                    those should have been reduced to just a mem.  */
                  || ((GET_CODE (operand) == MEM
                       || (GET_CODE (operand)== REG
                           && REGNO (operand) >= FIRST_PSEUDO_REGISTER))
+#ifndef WORD_REGISTER_OPERATIONS
                      && (((GET_MODE_BITSIZE (GET_MODE (operand))
                            < BIGGEST_ALIGNMENT)
                           && (GET_MODE_SIZE (operand_mode[i])
@@ -2763,7 +2830,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                              && INTEGRAL_MODE_P (GET_MODE (operand))
                              && LOAD_EXTEND_OP (GET_MODE (operand)) != NIL)
 #endif
-                         ))
+                         )
+#endif
+                     )
                  /* 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.  */
@@ -2814,11 +2883,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                break;
 
              case '?':
-               reject += 3;
+               reject += 6;
                break;
 
              case '!':
-               reject = 300;
+               reject = 600;
                break;
 
              case '#':
@@ -3150,16 +3219,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  && this_alternative_matches[i] < 0)
                bad = 1;
 
-             /* Alternative loses if it requires a type of reload not
-                permitted for this insn.  We can always reload SCRATCH
-                and objects with a REG_UNUSED note.  */
-             if (GET_CODE (operand) != SCRATCH
-                 && modified[i] != RELOAD_READ && no_output_reloads
-                 && ! find_reg_note (insn, REG_UNUSED, operand))
-               bad = 1;
-             else if (modified[i] != RELOAD_WRITE && no_input_reloads)
-               bad = 1;
-
              /* If this is a constant that is reloaded into the desired
                 class by copying it to memory first, count that as another
                 reload.  This is consistent with other code and is
@@ -3171,9 +3230,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              if (CONSTANT_P (operand)
                  /* force_const_mem does not accept HIGH.  */
                  && GET_CODE (operand) != HIGH
-                 && (PREFERRED_RELOAD_CLASS (operand,
+                 && ((PREFERRED_RELOAD_CLASS (operand,
                                              (enum reg_class) this_alternative[i])
-                     == NO_REGS)
+                      == NO_REGS)
+                     || no_input_reloads)
                  && operand_mode[i] != VOIDmode)
                {
                  const_to_mem = 1;
@@ -3193,6 +3253,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                      == NO_REGS))
                bad = 1;
 
+             /* Alternative loses if it requires a type of reload not
+                permitted for this insn.  We can always reload SCRATCH
+                and objects with a REG_UNUSED note.  */
+             else if (GET_CODE (operand) != SCRATCH
+                 && modified[i] != RELOAD_READ && no_output_reloads
+                 && ! find_reg_note (insn, REG_UNUSED, operand))
+               bad = 1;
+             else if (modified[i] != RELOAD_WRITE && no_input_reloads
+                      && ! const_to_mem)
+               bad = 1;
+
+
              /* We prefer to reload pseudos over reloading other things,
                 since such reloads may be able to be eliminated later.
                 If we are reloading a SCRATCH, we won't be generating any
@@ -3205,6 +3277,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                     && REGNO (operand) >= FIRST_PSEUDO_REGISTER)
                  && GET_CODE (operand) != SCRATCH
                  && ! (const_to_mem && constmemok))
+               reject += 2;
+
+             /* Input reloads can be inherited more often than output
+                reloads can be removed, so penalize output reloads.  */
+             if (operand_type[i] != RELOAD_FOR_INPUT
+                 && GET_CODE (operand) != SCRATCH)
                reject++;
            }
 
@@ -3245,7 +3323,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                                          this_alternative[i]))
                    this_alternative[i] = (int) preferred_class[i];
                  else
-                   reject += (1 + pref_or_nothing[i]);
+                   reject += (2 + 2 * pref_or_nothing[i]);
                }
            }
        }
@@ -3352,9 +3430,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
       /* REJECT, set by the ! and ? constraint characters and when a register
         would be reloaded into a non-preferred class, discourages the use of
-        this alternative for a reload goal.  REJECT is incremented by three
-        for each ? and one for each non-preferred class.  */
-      losers = losers * 3 + reject;
+        this alternative for a reload goal.  REJECT is incremented by six
+        for each ? and two for each non-preferred class.  */
+      losers = losers * 6 + reject;
 
       /* If this alternative can be made to work by reloading,
         and it needs less reloading than the others checked so far,
@@ -3428,7 +3506,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        abort ();
       error_for_asm (insn, "inconsistent operand constraints in an `asm'");
       /* Avoid further trouble with this insn.  */
-      PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+      PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
       n_reloads = 0;
       return;
     }
@@ -3513,9 +3591,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        && CONSTANT_P (recog_operand[i])
        /* force_const_mem does not accept HIGH.  */
        && GET_CODE (recog_operand[i]) != HIGH
-       && (PREFERRED_RELOAD_CLASS (recog_operand[i],
+       && ((PREFERRED_RELOAD_CLASS (recog_operand[i],
                                    (enum reg_class) goal_alternative[i])
-           == NO_REGS)
+            == NO_REGS)
+           || no_input_reloads)
        && operand_mode[i] != VOIDmode)
       {
        *recog_operand_loc[i] = recog_operand[i]
@@ -3631,7 +3710,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          {
            error_for_asm (insn, "inconsistent operand constraints in an `asm'");
            /* Avoid further trouble with this insn.  */
-           PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+           PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
            n_reloads = 0;
            return;
          }
@@ -3857,11 +3936,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                reload_when_needed[reload_secondary_out_reload[secondary_out_reload]] 
                  = RELOAD_FOR_OPADDR_ADDR;
            }
-         if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
-             || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
-           reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
-         else
-           reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+
+         reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
        }
 
       if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
@@ -3927,6 +4003,67 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            reload_in[j] = 0;
          }
 
+  /* Set which reloads must use registers not used in any group.  Start
+     with those that conflict with a group and then include ones that
+     conflict with ones that are already known to conflict with a group.  */
+
+  changed = 0;
+  for (i = 0; i < n_reloads; i++)
+    {
+      enum machine_mode mode = reload_inmode[i];
+      enum reg_class class = reload_reg_class[i];
+      int size;
+
+      if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
+       mode = reload_outmode[i];
+      size = CLASS_MAX_NREGS (class, mode);
+
+      if (size == 1)
+       for (j = 0; j < n_reloads; j++)
+         if ((CLASS_MAX_NREGS (reload_reg_class[j],
+                               (GET_MODE_SIZE (reload_outmode[j])
+                                > GET_MODE_SIZE (reload_inmode[j]))
+                               ? reload_outmode[j] : reload_inmode[j])
+              > 1)
+             && !reload_optional[j]
+             && (reload_in[j] != 0 || reload_out[j] != 0
+                 || reload_secondary_p[j])
+             && reloads_conflict (i, j)
+             && reg_classes_intersect_p (class, reload_reg_class[j]))
+           {
+             reload_nongroup[i] = 1;
+             changed = 1;
+             break;
+           }
+    }
+
+  while (changed)
+    {
+      changed = 0;
+
+      for (i = 0; i < n_reloads; i++)
+       {
+         enum machine_mode mode = reload_inmode[i];
+         enum reg_class class = reload_reg_class[i];
+         int size;
+
+         if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
+           mode = reload_outmode[i];
+         size = CLASS_MAX_NREGS (class, mode);
+
+         if (! reload_nongroup[i] && size == 1)
+           for (j = 0; j < n_reloads; j++)
+             if (reload_nongroup[j]
+                 && reloads_conflict (i, j)
+                 && reg_classes_intersect_p (class, reload_reg_class[j]))
+               {
+                 reload_nongroup[i] = 1;
+                 changed = 1;
+                 break;
+               }
+       }
+    }
+
 #else /* no REGISTER_CONSTRAINTS */
   int noperands;
   int insn_code_number;
@@ -4109,7 +4246,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
          if (rtx_varies_p (addr))
            addr = copy_rtx (addr);
 
-         x = gen_rtx (MEM, GET_MODE (x), addr);
+         x = gen_rtx_MEM (GET_MODE (x), addr);
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
          find_reloads_address (GET_MODE (x), NULL_PTR,
                                XEXP (x, 0),
@@ -4154,6 +4291,29 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
                                     GET_MODE (SUBREG_REG (x)))) != 0)
        return tem;
 
+      /* If the SUBREG is wider than a word, the above test will fail.
+        For example, we might have a SImode SUBREG of a DImode SUBREG_REG
+        for a 16 bit target, or a DImode SUBREG of a TImode SUBREG_REG for
+        a 32 bit target.  We still can - and have to - handle this
+        for non-paradoxical subregs of CONST_INTs.  */
+      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0
+         && GET_CODE (reg_equiv_constant[regno]) == CONST_INT
+         && (GET_MODE_SIZE (GET_MODE (x))
+             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+         {
+           int shift = SUBREG_WORD (x) * BITS_PER_WORD;
+           if (WORDS_BIG_ENDIAN)
+             shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
+                      - GET_MODE_BITSIZE (GET_MODE (x))
+                      - shift);
+           /* Here we use the knowledge that CONST_INTs have a
+              HOST_WIDE_INT field.  */
+           if (shift >= HOST_BITS_PER_WIDE_INT)
+             shift = HOST_BITS_PER_WIDE_INT - 1;
+           return GEN_INT (INTVAL (reg_equiv_constant[regno]) >> shift);
+         }
+
       if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
          && reg_equiv_constant[regno] != 0
          && GET_MODE (reg_equiv_constant[regno]) == VOIDmode)
@@ -4198,7 +4358,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
              offset -= MIN (size, UNITS_PER_WORD);
            }
          addr = plus_constant (addr, offset);
-         x = gen_rtx (MEM, GET_MODE (x), addr);
+         x = gen_rtx_MEM (GET_MODE (x), addr);
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
          find_reloads_address (GET_MODE (x), NULL_PTR,
                                XEXP (x, 0),
@@ -4224,7 +4384,9 @@ make_memloc (ad, regno)
      rtx ad;
      int regno;
 {
+#if 0
   register int i;
+#endif
   /* We must rerun eliminate_regs, in case the elimination
      offsets have changed.  */
   rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
@@ -4244,7 +4406,7 @@ make_memloc (ad, regno)
   if (rtx_varies_p (tem))
     tem = copy_rtx (tem);
 
-  tem = gen_rtx (MEM, GET_MODE (ad), tem);
+  tem = gen_rtx_MEM (GET_MODE (ad), tem);
   RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
   memlocs[n_memlocs++] = tem;
   return tem;
@@ -4370,6 +4532,24 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
        return 0;
     }
 
+#ifdef LEGITIMIZE_RELOAD_ADDRESS
+  do
+    {
+      if (memrefloc)
+       {
+         LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
+                                    ind_levels, win);
+       }
+      break;
+    win:
+      *memrefloc = copy_rtx (*memrefloc);
+      XEXP (*memrefloc, 0) = ad;
+      move_replacements (&ad, &XEXP (*memrefloc, 0));
+      return 1;
+    }
+  while (0);
+#endif
+
   /* The address is not valid.  We have to figure out why.  One possibility
      is that it is itself a MEM.  This can happen when the frame pointer is
      being eliminated, a pseudo is not allocated to a hard register, and the
@@ -4497,9 +4677,9 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
               || XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
           && ! memory_address_p (mode, ad))
     {
-      *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
-                          plus_constant (XEXP (XEXP (ad, 0), 0),
-                                         INTVAL (XEXP (ad, 1))),
+      *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
+                               plus_constant (XEXP (XEXP (ad, 0), 0),
+                                              INTVAL (XEXP (ad, 1))),
                           XEXP (XEXP (ad, 0), 1));
       find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0),
                                 reload_address_base_reg_class,
@@ -4522,10 +4702,10 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
               || XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
           && ! memory_address_p (mode, ad))
     {
-      *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
-                          XEXP (XEXP (ad, 0), 0),
-                          plus_constant (XEXP (XEXP (ad, 0), 1),
-                                         INTVAL (XEXP (ad, 1))));
+      *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
+                               XEXP (XEXP (ad, 0), 0),
+                               plus_constant (XEXP (XEXP (ad, 0), 1),
+                                              INTVAL (XEXP (ad, 1))));
       find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
                                 reload_address_base_reg_class,
                                 GET_MODE (ad), opnum, type, ind_levels);
@@ -4679,10 +4859,10 @@ form_sum (x, y)
       if (GET_CODE (y) == CONST)
        y = XEXP (y, 0);
 
-      return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, mode, x, y));
+      return gen_rtx_CONST (VOIDmode, gen_rtx_PLUS (mode, x, y));
     }
 
-  return gen_rtx (PLUS, mode, x, y);
+  return gen_rtx_PLUS (mode, x, y);
 }
 \f
 /* If ADDR is a sum containing a pseudo register that should be
@@ -4798,8 +4978,8 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
            op0 = SUBREG_REG (op0);
            code0 = GET_CODE (op0);
            if (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER)
-             op0 = gen_rtx (REG, word_mode,
-                            REGNO (op0) + SUBREG_WORD (orig_op0));
+             op0 = gen_rtx_REG (word_mode,
+                                REGNO (op0) + SUBREG_WORD (orig_op0));
          }
 
        if (GET_CODE (op1) == SUBREG)
@@ -4807,8 +4987,8 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
            op1 = SUBREG_REG (op1);
            code1 = GET_CODE (op1);
            if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER)
-             op1 = gen_rtx (REG, GET_MODE (op1),
-                            REGNO (op1) + SUBREG_WORD (orig_op1));
+             op1 = gen_rtx_REG (GET_MODE (op1),
+                                REGNO (op1) + SUBREG_WORD (orig_op1));
          }
 
        if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE 
@@ -4915,7 +5095,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
                                    &XEXP (tem, 0), opnum, type,
                                    ind_levels, insn);
              /* Put this inside a new increment-expression.  */
-             x = gen_rtx (GET_CODE (x), GET_MODE (x), tem);
+             x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
              /* Proceed to reload that, as if it contained a register.  */
            }
 
@@ -4936,7 +5116,9 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
               || !(context ? REGNO_OK_FOR_INDEX_P (regno)
                    : REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
            {
+#ifdef AUTO_INC_DEC
              register rtx link;
+#endif
              int reloadnum;
 
              /* If we can output the register afterwards, do so, this
@@ -5219,7 +5401,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
     {
       rtx tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
 
-      x = gen_rtx (PLUS, GET_MODE (x), XEXP (x, 0), tem);
+      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);
     }
@@ -5251,7 +5433,7 @@ subst_reloads ()
             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 = gen_rtx_REG (r->mode, REGNO (reloadreg));
 
          /* If we are putting this into a SUBREG and RELOADREG is a
             SUBREG, we would be making nested SUBREGs, so we have to fix
@@ -5318,6 +5500,25 @@ copy_replacements (x, y)
            }
        }
 }
+
+/* Change any replacements being done to *X to be done to *Y */
+
+void
+move_replacements (x, y)
+     rtx *x;
+     rtx *y;
+{
+  int i;
+
+  for (i = 0; i < n_replacements; i++)
+    if (replacements[i].subreg_loc == x)
+      replacements[i].subreg_loc = y;
+    else if (replacements[i].where == x)
+      {
+       replacements[i].where = y;
+       replacements[i].subreg_loc = 0;
+      }
+}
 \f
 /* If LOC was scheduled to be replaced by something, return the replacement.
    Otherwise, return *LOC.  */
@@ -5335,7 +5536,7 @@ find_replacement (loc)
       if (reloadreg && r->where == loc)
        {
          if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode)
-           reloadreg = gen_rtx (REG, r->mode, REGNO (reloadreg));
+           reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
 
          return reloadreg;
        }
@@ -5346,13 +5547,13 @@ find_replacement (loc)
             ??? Is it actually still ever a SUBREG?  If so, why?  */
 
          if (GET_CODE (reloadreg) == REG)
-           return gen_rtx (REG, GET_MODE (*loc),
-                           REGNO (reloadreg) + SUBREG_WORD (*loc));
+           return gen_rtx_REG (GET_MODE (*loc),
+                               REGNO (reloadreg) + SUBREG_WORD (*loc));
          else if (GET_MODE (reloadreg) == GET_MODE (*loc))
            return reloadreg;
          else
-           return gen_rtx (SUBREG, GET_MODE (*loc), SUBREG_REG (reloadreg),
-                           SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
+           return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
+                                  SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
        }
     }
 
@@ -5365,7 +5566,7 @@ find_replacement (loc)
       rtx y = find_replacement (&XEXP (*loc, 1));
 
       if (x != XEXP (*loc, 0) || y != XEXP (*loc, 1))
-       return gen_rtx (GET_CODE (*loc), GET_MODE (*loc), x, y);
+       return gen_rtx_fmt_ee (GET_CODE (*loc), GET_MODE (*loc), x, y);
     }
 
   return *loc;
@@ -5656,6 +5857,10 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
           && XEXP (goal, 0) == stack_pointer_rtx
           && CONSTANT_P (XEXP (goal, 1)))
     goal_const = need_stable_sp = 1;
+  else if (GET_CODE (goal) == PLUS
+          && XEXP (goal, 0) == frame_pointer_rtx
+          && CONSTANT_P (XEXP (goal, 1)))
+    goal_const = 1;
   else
     return 0;
 
@@ -6166,6 +6371,9 @@ debug_reload_to_stream (f)
       if (reload_optional[r])
        fprintf (f, ", optional");
 
+      if (reload_nongroup[r])
+       fprintf (stderr, ", nongroup");
+
       if (reload_inc[r] != 0)
        fprintf (f, ", inc by %d", reload_inc[r]);
 
@@ -6202,12 +6410,14 @@ debug_reload_to_stream (f)
       prefix = "\n\t";
       if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
        {
-         fprintf (f, "%ssecondary_in_icode = %s", prefix, insn_name[r]);
+         fprintf (stderr, "%ssecondary_in_icode = %s", prefix,
+                  insn_name[reload_secondary_in_icode[r]]);
          prefix = ", ";
        }
 
       if (reload_secondary_out_icode[r] != CODE_FOR_nothing)
-       fprintf (f, "%ssecondary_out_icode = %s", prefix, insn_name[r]);
+       fprintf (stderr, "%ssecondary_out_icode = %s", prefix,
+                insn_name[reload_secondary_out_icode[r]]);
 
       fprintf (f, "\n");
     }