OSDN Git Service

(find_barrier): Always use get_attr_length to compute length of
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 9223c21..9f437b6 100644 (file)
@@ -1,5 +1,5 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
-   Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <stdio.h>
@@ -33,6 +34,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "recog.h"
 #include "basic-block.h"
 #include "output.h"
+#include "real.h"
 
 /* This file contains the reload pass of the compiler, which is
    run after register allocation has been done.  It checks that
@@ -168,6 +170,11 @@ static HARD_REG_SET bad_spill_regs;
    elements that are actually valid; new ones are added at the end.  */
 static short spill_regs[FIRST_PSEUDO_REGISTER];
 
+/* Index of last register assigned as a spill register.  We allocate in
+   a round-robin fashion.  */
+
+static int last_spill_reg;
+
 /* Describes order of preference for putting regs into spill_regs.
    Contains the numbers of all the hard regs, in order most preferred first.
    This order is different for each function.
@@ -327,7 +334,7 @@ struct hard_reg_n_uses { int regno; int uses; };
 \f
 static int possible_group_p            PROTO((int, int *));
 static void count_possible_groups      PROTO((int *, enum machine_mode *,
-                                              int *));
+                                              int *, int));
 static int modes_equiv_for_class_p     PROTO((enum machine_mode,
                                               enum machine_mode,
                                               enum reg_class));
@@ -691,6 +698,9 @@ reload (first, global, dumpfile)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     spill_reg_order[i] = -1;
 
+  /* Initialize to -1, which means take the first spill register.  */
+  last_spill_reg = -1;
+
   /* On most machines, we can't use any register explicitly used in the
      rtl as a spill register.  But on some, we have to.  Those will have
      taken care to keep the life of hard regs as short as possible.  */
@@ -915,7 +925,7 @@ reload (first, global, dumpfile)
              int did_elimination = 0;
 
              /* To compute the number of reload registers of each class 
-                needed for an insn, we must similate what choose_reload_regs
+                needed for an insn, we must simulate what choose_reload_regs
                 can do.  We do this by splitting an insn into an "input" and
                 an "output" part.  RELOAD_OTHER reloads are used in both. 
                 The input part uses those reloads, RELOAD_FOR_INPUT reloads,
@@ -1153,7 +1163,8 @@ reload (first, global, dumpfile)
                      if (other_mode != VOIDmode && other_mode != allocate_mode
                          && ! modes_equiv_for_class_p (allocate_mode,
                                                        other_mode, class))
-                       abort ();
+                       fatal_insn ("Two dissimilar machine modes both need groups of consecutive regs of the same class",
+                                   insn);
                    }
                  else if (size == 1)
                    {
@@ -1328,10 +1339,10 @@ reload (first, global, dumpfile)
                     need only in the smallest class in which it
                     is required.  */
 
-                 bcopy (insn_needs.other.regs[0], basic_needs,
-                        sizeof basic_needs);
-                 bcopy (insn_needs.other.groups, basic_groups,
-                        sizeof basic_groups);
+                 bcopy ((char *) insn_needs.other.regs[0],
+                        (char *) basic_needs, sizeof basic_needs);
+                 bcopy ((char *) insn_needs.other.groups,
+                        (char *) basic_groups, sizeof basic_groups);
 
                  for (i = 0; i < N_REG_CLASSES; i++)
                    {
@@ -1349,19 +1360,14 @@ reload (first, global, dumpfile)
                    }
 
                  /* Now count extra regs if there might be a conflict with
-                    the return value register.
+                    the return value register. */
 
-                    ??? This is not quite correct because we don't properly
-                    handle the case of groups, but if we end up doing
-                    something wrong, it either will end up not mattering or
-                    we will abort elsewhere.  */
-                  
                  for (r = regno; r < regno + nregs; r++)
                    if (spill_reg_order[r] >= 0)
                      for (i = 0; i < N_REG_CLASSES; i++)
                        if (TEST_HARD_REG_BIT (reg_class_contents[i], r))
                          {
-                           if (basic_needs[i] > 0 || basic_groups[i] > 0)
+                           if (basic_needs[i] > 0)
                              {
                                enum reg_class *p;
 
@@ -1370,6 +1376,15 @@ reload (first, global, dumpfile)
                                while (*p != LIM_REG_CLASSES)
                                  insn_needs.other.regs[0][(int) *p++]++;
                              }
+                           if (basic_groups[i] > 0)
+                             {
+                               enum reg_class *p;
+
+                               insn_needs.other.groups[i]++;
+                               p = reg_class_superclasses[i];
+                               while (*p != LIM_REG_CLASSES)
+                                 insn_needs.other.groups[(int) *p++]++;
+                             }
                          }
                }
 #endif /* SMALL_REGISTER_CLASSES */
@@ -1533,7 +1548,7 @@ reload (first, global, dumpfile)
 
       /* Put all registers spilled so far back in potential_reload_regs, but
         put them at the front, since we've already spilled most of the
-        psuedos in them (we might have left some pseudos unspilled if they
+        pseudos in them (we might have left some pseudos unspilled if they
         were in a block that didn't need any spill registers of a conflicting
         class.  We used to try to mark off the need for those registers,
         but doing so properly is very complex and reallocating them is the
@@ -1603,7 +1618,8 @@ reload (first, global, dumpfile)
              /* If any single spilled regs happen to form groups,
                 count them now.  Maybe we don't really need
                 to spill another group.  */
-             count_possible_groups (group_size, group_mode, max_groups);
+             count_possible_groups (group_size, group_mode, max_groups,
+                                    class);
 
              if (max_groups[class] <= 0)
                break;
@@ -1647,7 +1663,11 @@ reload (first, global, dumpfile)
                          max_groups[class]--;
                          p = reg_class_superclasses[class];
                          while (*p != LIM_REG_CLASSES)
-                           max_groups[(int) *p++]--;
+                           {
+                             if (group_size [(int) *p] <= group_size [class])
+                               max_groups[(int) *p]--;
+                             p++;
+                           }
 
                          /* Indicate both these regs are part of a group.  */
                          SET_HARD_REG_BIT (counted_for_groups, j);
@@ -1762,8 +1782,12 @@ reload (first, global, dumpfile)
                              max_groups[class]--;
                              p = reg_class_superclasses[class];
                              while (*p != LIM_REG_CLASSES)
-                               max_groups[(int) *p++]--;
-
+                               {
+                                 if (group_size [(int) *p]
+                                     <= group_size [class])
+                                   max_groups[(int) *p]--;
+                                 p++;
+                               }
                              break;
                            }
                        }
@@ -2063,68 +2087,69 @@ possible_group_p (regno, max_groups)
   return 0;
 }
 \f
-/* Count any groups that can be formed from the registers recently spilled.
-   This is done class by class, in order of ascending class number.  */
+/* Count any groups of CLASS that can be formed from the registers recently
+   spilled.  */
 
 static void
-count_possible_groups (group_size, group_mode, max_groups)
+count_possible_groups (group_size, group_mode, max_groups, class)
      int *group_size;
      enum machine_mode *group_mode;
      int *max_groups;
+     int class;
 {
-  int i;
+  HARD_REG_SET new;
+  int i, j;
+
   /* Now find all consecutive groups of spilled registers
      and mark each group off against the need for such groups.
      But don't count them against ordinary need, yet.  */
 
-  for (i = 0; i < N_REG_CLASSES; i++)
-    if (group_size[i] > 1)
+  if (group_size[class] == 0)
+    return;
+
+  CLEAR_HARD_REG_SET (new);
+
+  /* Make a mask of all the regs that are spill regs in class I.  */
+  for (i = 0; i < n_spills; i++)
+    if (TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
+       && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[i])
+       && ! TEST_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]))
+      SET_HARD_REG_BIT (new, spill_regs[i]);
+
+  /* Find each consecutive group of them.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER && max_groups[class] > 0; i++)
+    if (TEST_HARD_REG_BIT (new, i)
+       && i + group_size[class] <= FIRST_PSEUDO_REGISTER
+       && HARD_REGNO_MODE_OK (i, group_mode[class]))
       {
-       HARD_REG_SET new;
-       int j;
-
-       CLEAR_HARD_REG_SET (new);
-
-       /* Make a mask of all the regs that are spill regs in class I.  */
-       for (j = 0; j < n_spills; j++)
-         if (TEST_HARD_REG_BIT (reg_class_contents[i], spill_regs[j])
-             && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[j])
-             && ! TEST_HARD_REG_BIT (counted_for_nongroups,
-                                     spill_regs[j]))
-           SET_HARD_REG_BIT (new, spill_regs[j]);
-
-       /* Find each consecutive group of them.  */
-       for (j = 0; j < FIRST_PSEUDO_REGISTER && max_groups[i] > 0; j++)
-         if (TEST_HARD_REG_BIT (new, j)
-             && j + group_size[i] <= FIRST_PSEUDO_REGISTER
-             /* Next line in case group-mode for this class
-                demands an even-odd pair.  */
-             && HARD_REGNO_MODE_OK (j, group_mode[i]))
-           {
-             int k;
-             for (k = 1; k < group_size[i]; k++)
-               if (! TEST_HARD_REG_BIT (new, j + k))
-                 break;
-             if (k == group_size[i])
-               {
-                 /* We found a group.  Mark it off against this class's
-                    need for groups, and against each superclass too.  */
-                 register enum reg_class *p;
-                 max_groups[i]--;
-                 p = reg_class_superclasses[i];
-                 while (*p != LIM_REG_CLASSES)
-                   max_groups[(int) *p++]--;
-                 /* Don't count these registers again.  */
-                 for (k = 0; k < group_size[i]; k++)
-                   SET_HARD_REG_BIT (counted_for_groups, j + k);
-               }
-             /* Skip to the last reg in this group.  When j is incremented
-                above, it will then point to the first reg of the next
-                possible group.  */
-             j += k - 1;
-           }
-      }
+       for (j = 1; j < group_size[class]; j++)
+         if (! TEST_HARD_REG_BIT (new, i + j))
+           break;
+
+       if (j == group_size[class])
+         {
+           /* We found a group.  Mark it off against this class's need for
+              groups, and against each superclass too.  */
+           register enum reg_class *p;
+
+           max_groups[class]--;
+           p = reg_class_superclasses[class];
+           while (*p != LIM_REG_CLASSES)
+             {
+               if (group_size [(int) *p] <= group_size [class])
+                 max_groups[(int) *p]--;
+               p++;
+             }
+
+           /* Don't count these registers again.  */
+           for (j = 0; j < group_size[class]; j++)
+             SET_HARD_REG_BIT (counted_for_groups, i + j);
+         }
 
+       /* Skip to the last reg in this group.  When i is incremented above,
+          it will then point to the first reg of the next possible group.  */
+       i += j - 1;
+      }
 }
 \f
 /* ALLOCATE_MODE is a register mode that needs to be reloaded.  OTHER_MODE is
@@ -2165,7 +2190,7 @@ spill_failure (insn)
   if (asm_noperands (PATTERN (insn)) >= 0)
     error_for_asm (insn, "`asm' needs too many reloads");
   else
-    abort ();
+    fatal_insn ("Unable to find a register to spill.", insn);
 }
 
 /* Add a new register to the tables of available spill-registers
@@ -2325,13 +2350,14 @@ alter_reg (i, from_reg)
        {
          /* No known place to spill from => no slot to reuse.  */
          x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, -1);
-#if BYTES_BIG_ENDIAN
-         /* Cancel the  big-endian correction done in assign_stack_local.
-            Get the address of the beginning of the slot.
-            This is so we can do a big-endian correction unconditionally
-            below.  */
-         adjust = inherent_size - total_size;
-#endif
+         if (BYTES_BIG_ENDIAN)
+           /* Cancel the  big-endian correction done in assign_stack_local.
+              Get the address of the beginning of the slot.
+              This is so we can do a big-endian correction unconditionally
+              below.  */
+           adjust = inherent_size - total_size;
+
+         RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
        }
       /* Reuse a stack slot if possible.  */
       else if (spill_stack_slot[from_reg] != 0
@@ -2345,6 +2371,7 @@ alter_reg (i, from_reg)
          /* Compute maximum size needed, both for inherent size
             and for total size.  */
          enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
+         rtx stack_slot;
          if (spill_stack_slot[from_reg])
            {
              if (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg]))
@@ -2355,23 +2382,28 @@ alter_reg (i, from_reg)
            }
          /* Make a slot with that size.  */
          x = assign_stack_local (mode, total_size, -1);
-#if BYTES_BIG_ENDIAN
-         /* Cancel the  big-endian correction done in assign_stack_local.
-            Get the address of the beginning of the slot.
-            This is so we can do a big-endian correction unconditionally
-            below.  */
-         adjust = GET_MODE_SIZE (mode) - total_size;
-#endif
-         spill_stack_slot[from_reg] = x;
+         stack_slot = x;
+         if (BYTES_BIG_ENDIAN)
+           {
+             /* Cancel the  big-endian correction done in assign_stack_local.
+                Get the address of the beginning of the slot.
+                This is so we can do a big-endian correction unconditionally
+                below.  */
+             adjust = GET_MODE_SIZE (mode) - total_size;
+             if (adjust)
+               stack_slot = gen_rtx (MEM, mode_for_size (total_size
+                                                         * BITS_PER_UNIT,
+                                                         MODE_INT, 1),
+                                     plus_constant (XEXP (x, 0), adjust));
+           }
+         spill_stack_slot[from_reg] = stack_slot;
          spill_stack_slot_width[from_reg] = total_size;
        }
 
-#if BYTES_BIG_ENDIAN
       /* On a big endian machine, the "address" of the slot
         is the address of the low part that fits its inherent mode.  */
-      if (inherent_size < total_size)
+      if (BYTES_BIG_ENDIAN && inherent_size < total_size)
        adjust += (total_size - inherent_size);
-#endif /* BYTES_BIG_ENDIAN */
 
       /* If we have any adjustment to make, or if the stack slot is the
         wrong mode, make a new stack slot.  */
@@ -2766,7 +2798,7 @@ eliminate_regs (x, mem_mode, insn)
       /* If this is the product of an eliminable register and a 
         constant, apply the distribute law and move the constant out
         so that we have (plus (mult ..) ..).  This is needed in order
-        to keep load-address insns valid.   This case is pathalogical.
+        to keep load-address insns valid.   This case is pathological.
         We ignore the possibility of overflow here.  */
       if (GET_CODE (XEXP (x, 0)) == REG
          && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
@@ -2916,18 +2948,21 @@ eliminate_regs (x, mem_mode, insn)
                 smaller.  So leave the SUBREG then.  */
              && ! (GET_CODE (SUBREG_REG (x)) == REG
                    && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
-                   && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD)
+                   && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD
+                   && (GET_MODE_SIZE (GET_MODE (x))
+                       > GET_MODE_SIZE (GET_MODE (new)))
+                   && INTEGRAL_MODE_P (GET_MODE (new))
+                   && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
 #endif
              )
            {
              int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
              enum machine_mode mode = GET_MODE (x);
 
-#if BYTES_BIG_ENDIAN
-             offset += (MIN (UNITS_PER_WORD,
-                             GET_MODE_SIZE (GET_MODE (new)))
-                        - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-#endif
+             if (BYTES_BIG_ENDIAN)
+               offset += (MIN (UNITS_PER_WORD,
+                               GET_MODE_SIZE (GET_MODE (new)))
+                          - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
 
              PUT_MODE (new, mode);
              XEXP (new, 0) = plus_constant (XEXP (new, 0), offset);
@@ -3201,7 +3236,7 @@ eliminate_regs_in_insn (insn, replace)
               will delete it in reload_as_needed once we know that this
               elimination is, in fact, being done.
 
-              If REPLACE isn't set, we can't delete this insn, but neededn't
+              If REPLACE isn't set, we can't delete this insn, but needn't
               process it since it won't be used unless something changes.  */
            if (replace)
              delete_dead_insn (insn);
@@ -3337,7 +3372,7 @@ eliminate_regs_in_insn (insn, replace)
     }
 
  done:
-  /* If we changed something, perform elmination in REG_NOTES.  This is
+  /* If we changed something, perform elimination in REG_NOTES.  This is
      needed even when REPLACE is zero because a REG_DEAD note might refer
      to a register that we eliminate and could cause a different number
      of spill registers to be needed in the final reload pass than in
@@ -3770,6 +3805,7 @@ reload_as_needed (first, live_known)
       else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
        {
          rtx avoid_return_reg = 0;
+         rtx oldpat = PATTERN (insn);
 
 #ifdef SMALL_REGISTER_CLASSES
          /* Set avoid_return_reg if this is an insn
@@ -3850,7 +3886,7 @@ reload_as_needed (first, live_known)
                        && ! reload_optional[i]
                        && (reload_in[i] != 0 || reload_out[i] != 0
                            || reload_secondary_p[i] != 0))
-                     abort ();
+                     fatal_insn ("Non-optional registers need a spill register", insn);
 
              /* Now compute which reload regs to reload them into.  Perhaps
                 reusing reload regs from previous insns, or else output
@@ -3899,7 +3935,7 @@ reload_as_needed (first, live_known)
             for this insn in order to be stored in
             (obeying register constraints).  That is correct; such reload
             registers ARE still valid.  */
-         note_stores (PATTERN (insn), forget_old_reloads_1);
+         note_stores (oldpat, forget_old_reloads_1);
 
          /* There may have been CLOBBER insns placed after INSN.  So scan
             between INSN and NEXT and use them to forget old reloads.  */
@@ -4657,11 +4693,6 @@ rtx reload_override_in[MAX_RELOADS];
    or -1 if we did not need one of the spill registers for this reload.  */
 int reload_spill_index[MAX_RELOADS];
 
-/* Index of last register assigned as a spill register.  We allocate in
-   a round-robin fashio.  */
-
-static int last_spill_reg = 0;
-
 /* Find a spill register to use as a reload register for reload R.
    LAST_RELOAD is non-zero if this is the last reload for the insn being
    processed.
@@ -4846,7 +4877,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
  failure:
   if (asm_noperands (PATTERN (insn)) < 0)
     /* It's the compiler's fault.  */
-    abort ();
+    fatal_insn ("Could not find a spill register", insn);
 
   /* It's the user's fault; the operand's mode and constraint
      don't match.  Disable this reload so we don't crash in final.  */
@@ -5619,6 +5650,7 @@ emit_reload_insns (insn)
   rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
   rtx operand_reload_insns = 0;
   rtx other_operand_reload_insns = 0;
+  rtx other_output_reload_insns = 0;
   rtx following_insn = NEXT_INSN (insn);
   rtx before_insn = insn;
   int special;
@@ -5638,7 +5670,9 @@ emit_reload_insns (insn)
     {
       register rtx old;
       rtx oldequiv_reg = 0;
-      rtx store_insn = 0;
+
+      if (reload_spill_index[j] >= 0)
+       new_spill_reg_store[reload_spill_index[j]] = 0;
 
       old = reload_in[j];
       if (old != 0 && ! reload_inherited[j]
@@ -6020,9 +6054,9 @@ emit_reload_insns (insn)
                                           third_reload_reg)));
                            }
                          else
-                           gen_input_reload (second_reload_reg, oldequiv,
-                                             reload_opnum[j],
-                                             reload_when_needed[j]);
+                           gen_reload (second_reload_reg, oldequiv,
+                                       reload_opnum[j],
+                                       reload_when_needed[j]);
 
                          oldequiv = second_reload_reg;
                        }
@@ -6031,8 +6065,8 @@ emit_reload_insns (insn)
 #endif
 
              if (! special && ! rtx_equal_p (reloadreg, oldequiv))
-               gen_input_reload (reloadreg, oldequiv, reload_opnum[j],
-                                 reload_when_needed[j]);
+               gen_reload (reloadreg, oldequiv, reload_opnum[j],
+                           reload_when_needed[j]);
 
 #if defined(SECONDARY_INPUT_RELOAD_CLASS) && defined(PRESERVE_DEATH_INFO_REGNO_P)
              /* We may have to make a REG_DEAD note for the secondary reload
@@ -6226,6 +6260,16 @@ emit_reload_insns (insn)
              XEXP (note, 0) = reload_reg_rtx[j];
              continue;
            }
+         /* Likewise for a SUBREG of an operand that dies.  */
+         else if (GET_CODE (old) == SUBREG
+                  && GET_CODE (SUBREG_REG (old)) == REG
+                  && 0 != (note = find_reg_note (insn, REG_UNUSED,
+                                                 SUBREG_REG (old))))
+           {
+             XEXP (note, 0) = gen_lowpart_common (GET_MODE (old),
+                                                  reload_reg_rtx[j]);
+             continue;
+           }
          else if (GET_CODE (old) == SCRATCH)
            /* If we aren't optimizing, there won't be a REG_UNUSED note,
               but we don't want to make an output reload.  */
@@ -6245,7 +6289,10 @@ emit_reload_insns (insn)
          if (GET_CODE (insn) == JUMP_INSN)
            abort ();
 
-         push_to_sequence (output_reload_insns[reload_opnum[j]]);
+         if (reload_when_needed[j] == RELOAD_OTHER)
+           push_to_sequence (other_output_reload_insns);
+         else
+           push_to_sequence (output_reload_insns[reload_opnum[j]]);
 
          /* Determine the mode to reload in.
             See comments above (for input reloading).  */
@@ -6256,7 +6303,7 @@ emit_reload_insns (insn)
              /* VOIDmode should never happen for an output.  */
              if (asm_noperands (PATTERN (insn)) < 0)
                /* It's the compiler's fault.  */
-               abort ();
+               fatal_insn ("VOIDmode on an output", insn);
              error_for_asm (insn, "output operand is constant in `asm'");
              /* Prevent crash--use something we know is valid.  */
              mode = word_mode;
@@ -6269,7 +6316,7 @@ emit_reload_insns (insn)
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
 
          /* If we need two reload regs, set RELOADREG to the intermediate
-            one, since it will be stored into OUT.  We might need a secondary
+            one, since it will be stored into OLD.  We might need a secondary
             register only for an input reload, so check again here.  */
 
          if (reload_secondary_out_reload[j] >= 0)
@@ -6299,10 +6346,10 @@ emit_reload_insns (insn)
                    {
                      /* See if we need both a scratch and intermediate reload
                         register.  */
+
                      int secondary_reload = reload_secondary_out_reload[j];
                      enum insn_code tertiary_icode
                        = reload_secondary_out_icode[secondary_reload];
-                     rtx pat;
 
                      if (GET_MODE (reloadreg) != mode)
                        reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
@@ -6311,44 +6358,36 @@ emit_reload_insns (insn)
                        {
                          rtx third_reloadreg
                            = reload_reg_rtx[reload_secondary_out_reload[secondary_reload]];
-                         pat = (GEN_FCN (tertiary_icode)
-                                (reloadreg, second_reloadreg, third_reloadreg));
-                       }
-#ifdef SECONDARY_MEMORY_NEEDED
-                     /* If we need a memory location to do the move, do it that way.  */
-                     else if (GET_CODE (reloadreg) == REG
-                              && REGNO (reloadreg) < FIRST_PSEUDO_REGISTER
-                              && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (reloadreg)),
-                                          REGNO_REG_CLASS (REGNO (second_reloadreg)),
-                                          GET_MODE (second_reloadreg)))
-                       {
-                         /* Get the memory to use and rewrite both registers
-                            to its mode.  */
-                         rtx loc
-                           = get_secondary_mem (reloadreg,
-                                                GET_MODE (second_reloadreg),
-                                                reload_opnum[j],
-                                                reload_when_needed[j]);
-                         rtx tmp_reloadreg;
-                           
-                         if (GET_MODE (loc) != GET_MODE (second_reloadreg))
-                           second_reloadreg = gen_rtx (REG, GET_MODE (loc),
-                                                       REGNO (second_reloadreg));
-                         
-                         if (GET_MODE (loc) != GET_MODE (reloadreg))
-                           tmp_reloadreg = gen_rtx (REG, GET_MODE (loc),
-                                                    REGNO (reloadreg));
-                         else
-                           tmp_reloadreg = reloadreg;
-                         
-                         emit_move_insn (loc, second_reloadreg);
-                         pat = gen_move_insn (tmp_reloadreg, loc);
+                         rtx tem;
+
+                         /* Copy primary reload reg to secondary reload reg.
+                            (Note that these have been swapped above, then
+                            secondary reload reg to OLD using our insn.  */
+
+                         /* If REAL_OLD is a paradoxical SUBREG, remove it
+                            and try to put the opposite SUBREG on
+                            RELOADREG.  */
+                         if (GET_CODE (real_old) == SUBREG
+                             && (GET_MODE_SIZE (GET_MODE (real_old))
+                                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old))))
+                             && 0 != (tem = gen_lowpart_common
+                                      (GET_MODE (SUBREG_REG (real_old)),
+                                       reloadreg)))
+                           real_old = SUBREG_REG (real_old), reloadreg = tem;
+
+                         gen_reload (reloadreg, second_reloadreg,
+                                     reload_opnum[j], reload_when_needed[j]);
+                         emit_insn ((GEN_FCN (tertiary_icode)
+                                     (real_old, reloadreg, third_reloadreg)));
+                         special = 1;
                        }
-#endif
+
                      else
-                       pat = gen_move_insn (reloadreg, second_reloadreg);
+                       /* Copy between the reload regs here and then to
+                          OUT later.  */
 
-                     emit_insn (pat);
+                       gen_reload (reloadreg, second_reloadreg,
+                                   reload_opnum[j], reload_when_needed[j]);
                    }
                }
            }
@@ -6356,34 +6395,8 @@ emit_reload_insns (insn)
 
          /* Output the last reload insn.  */
          if (! special)
-           {
-#ifdef SECONDARY_MEMORY_NEEDED
-             /* If we need a memory location to do the move, do it that way.  */
-             if (GET_CODE (old) == REG && REGNO (old) < FIRST_PSEUDO_REGISTER
-                 && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (old)),
-                                             REGNO_REG_CLASS (REGNO (reloadreg)),
-                                             GET_MODE (reloadreg)))
-               {
-                 /* Get the memory to use and rewrite both registers to
-                    its mode.  */
-                 rtx loc = get_secondary_mem (old, GET_MODE (reloadreg),
-                                              reload_opnum[j],
-                                              reload_when_needed[j]);
-
-                 if (GET_MODE (loc) != GET_MODE (reloadreg))
-                   reloadreg = gen_rtx (REG, GET_MODE (loc),
-                                        REGNO (reloadreg));
-
-                 if (GET_MODE (loc) != GET_MODE (old))
-                   old = gen_rtx (REG, GET_MODE (loc), REGNO (old));
-
-                 emit_insn (gen_move_insn (loc, reloadreg));
-                 emit_insn (gen_move_insn (old, loc));
-               }
-             else
-#endif
-               emit_insn (gen_move_insn (old, reloadreg));
-           }
+           gen_reload (old, reloadreg, reload_opnum[j],
+                       reload_when_needed[j]);
 
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
          /* If final will look at death notes for this reg,
@@ -6418,17 +6431,18 @@ emit_reload_insns (insn)
                   reg_has_output_reload will make this do nothing.  */
                note_stores (PATTERN (p), forget_old_reloads_1);
 
-               if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p)))
-                 store_insn = p;
+               if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p))
+                   && reload_spill_index[j] >= 0)
+                 new_spill_reg_store[reload_spill_index[j]] = p;
              }
 
-         output_reload_insns[reload_opnum[j]] = get_insns ();
-         end_sequence ();
+         if (reload_when_needed[j] == RELOAD_OTHER)
+           other_output_reload_insns = get_insns ();
+         else
+           output_reload_insns[reload_opnum[j]] = get_insns ();
 
+         end_sequence ();
        }
-
-      if (reload_spill_index[j] >= 0)
-       new_spill_reg_store[reload_spill_index[j]] = store_insn;
     }
 
   /* Now write all the insns we made for reloads in the order expected by
@@ -6449,7 +6463,9 @@ emit_reload_insns (insn)
      After the insn being reloaded, we write the following:
 
      For each operand, any RELOAD_FOR_OUTPUT_ADDRESS reload followed by
-     the RELOAD_FOR_OUTPUT reload for that operand.  */
+     the RELOAD_FOR_OUTPUT reload for that operand.
+
+     Any RELOAD_OTHER output reloads.  */
 
   emit_insns_before (other_input_address_reload_insns, before_insn);
   emit_insns_before (other_input_reload_insns, before_insn);
@@ -6469,6 +6485,8 @@ emit_reload_insns (insn)
       emit_insns_before (output_reload_insns[j], following_insn);
     }
 
+  emit_insns_before (other_output_reload_insns, following_insn);
+
   /* Move death notes from INSN
      to output-operand-address and output reload insns.  */
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
@@ -6642,27 +6660,47 @@ emit_reload_insns (insn)
       if (i < 0 && reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
        {
          register int nregno = REGNO (reload_out[r]);
-         int num_regs = HARD_REGNO_NREGS (nregno, GET_MODE (reload_out[r]));
+         if (nregno >= FIRST_PSEUDO_REGISTER)
+           reg_last_reload_reg[nregno] = 0;
+         else
+           {
+             int num_regs = HARD_REGNO_NREGS (nregno,GET_MODE (reload_out[r]));
 
-         while (num_regs-- > 0)
-           reg_last_reload_reg[nregno + num_regs] = 0;
+             while (num_regs-- > 0)
+               reg_last_reload_reg[nregno + num_regs] = 0;
+           }
        }
     }
 }
 \f
-/* Emit code to perform an input reload of IN to RELOADREG.  IN is from
-   operand OPNUM with reload type TYPE. 
+/* Emit code to perform a reload from IN (which may be a reload register) to
+   OUT (which may also be a reload register).  IN or OUT is from operand
+   OPNUM with reload type TYPE. 
 
    Returns first insn emitted.  */
 
 rtx
-gen_input_reload (reloadreg, in, opnum, type)
-     rtx reloadreg;
+gen_reload (out, in, opnum, type)
+     rtx out;
      rtx in;
      int opnum;
      enum reload_type type;
 {
   rtx last = get_last_insn ();
+  rtx tem;
+
+  /* If IN is a paradoxical SUBREG, remove it and try to put the
+     opposite SUBREG on OUT.  Likewise for a paradoxical SUBREG on OUT.  */
+  if (GET_CODE (in) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (in))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+      && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
+    in = SUBREG_REG (in), out = tem;
+  else if (GET_CODE (out) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (out))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+      && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (out)), in)) != 0)
+    out = SUBREG_REG (out), in = tem;
 
   /* How to do this reload can get quite tricky.  Normally, we are being
      asked to reload a simple operand, such as a MEM, a constant, or a pseudo
@@ -6724,13 +6762,13 @@ gen_input_reload (reloadreg, in, opnum, type)
         it will be A = A + B as constrain_operands expects. */
 
       if (GET_CODE (XEXP (in, 1)) == REG
-         && REGNO (reloadreg) == REGNO (XEXP (in, 1)))
+         && REGNO (out) == REGNO (XEXP (in, 1)))
        tem = op0, op0 = op1, op1 = tem;
 
       if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
        in = gen_rtx (PLUS, GET_MODE (in), op0, op1);
 
-      insn = emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+      insn = emit_insn (gen_rtx (SET, VOIDmode, out, in));
       code = recog_memoized (insn);
 
       if (code >= 0)
@@ -6759,16 +6797,16 @@ gen_input_reload (reloadreg, in, opnum, type)
              && REGNO (op1) >= FIRST_PSEUDO_REGISTER))
        tem = op0, op0 = op1, op1 = tem;
 
-      emit_insn (gen_move_insn (reloadreg, op0));
+      emit_insn (gen_move_insn (out, op0));
 
-      /* If OP0 and OP1 are the same, we can use RELOADREG for OP1.
+      /* If OP0 and OP1 are the same, we can use OUT for OP1.
         This fixes a problem on the 32K where the stack pointer cannot
         be used as an operand of an add insn.  */
 
       if (rtx_equal_p (op0, op1))
-       op1 = reloadreg;
+       op1 = out;
 
-      insn = emit_insn (gen_add2_insn (reloadreg, op1));
+      insn = emit_insn (gen_add2_insn (out, op1));
 
       /* If that failed, copy the address register to the reload register.
         Then add the constant to the reload register. */
@@ -6787,43 +6825,44 @@ gen_input_reload (reloadreg, in, opnum, type)
 
       delete_insns_since (last);
 
-      emit_insn (gen_move_insn (reloadreg, op1));
-      emit_insn (gen_add2_insn (reloadreg, op0));
+      emit_insn (gen_move_insn (out, op1));
+      emit_insn (gen_add2_insn (out, op0));
     }
 
 #ifdef SECONDARY_MEMORY_NEEDED
   /* If we need a memory location to do the move, do it that way.  */
   else if (GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER
+          && GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER
           && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
-                                      REGNO_REG_CLASS (REGNO (reloadreg)),
-                                      GET_MODE (reloadreg)))
+                                      REGNO_REG_CLASS (REGNO (out)),
+                                      GET_MODE (out)))
     {
       /* Get the memory to use and rewrite both registers to its mode.  */
-      rtx loc = get_secondary_mem (in, GET_MODE (reloadreg), opnum, type);
+      rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type);
 
-      if (GET_MODE (loc) != GET_MODE (reloadreg))
-       reloadreg = gen_rtx (REG, GET_MODE (loc), REGNO (reloadreg));
+      if (GET_MODE (loc) != GET_MODE (out))
+       out = gen_rtx (REG, GET_MODE (loc), REGNO (out));
 
       if (GET_MODE (loc) != GET_MODE (in))
        in = gen_rtx (REG, GET_MODE (loc), REGNO (in));
 
       emit_insn (gen_move_insn (loc, in));
-      emit_insn (gen_move_insn (reloadreg, loc));
+      emit_insn (gen_move_insn (out, loc));
     }
 #endif
 
   /* If IN is a simple operand, use gen_move_insn.  */
   else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
-    emit_insn (gen_move_insn (reloadreg, in));
+    emit_insn (gen_move_insn (out, in));
 
 #ifdef HAVE_reload_load_address
   else if (HAVE_reload_load_address)
-    emit_insn (gen_reload_load_address (reloadreg, in));
+    emit_insn (gen_reload_load_address (out, in));
 #endif
 
-  /* Otherwise, just write (set REGLOADREG IN) and hope for the best.  */
+  /* Otherwise, just write (set OUT IN) and hope for the best.  */
   else
-    emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+    emit_insn (gen_rtx (SET, VOIDmode, out, in));
 
   /* Return the first insn emitted.
      We can not just return get_last_insn, because there may have
@@ -6970,7 +7009,7 @@ inc_for_reload (reloadreg, value, inc_amount)
     emit_insn (gen_move_insn (reloadreg, incloc));
 
   /* See if we can directly increment INCLOC.  Use a method similar to that
-     in gen_input_reload.  */
+     in gen_reload.  */
 
   last = get_last_insn ();
   add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc,