OSDN Git Service

PR c++/38543
[pf3gnuchains/gcc-fork.git] / gcc / caller-save.c
index 2d0925a..39bccc4 100644 (file)
@@ -1,6 +1,7 @@
 /* Save and restore call-clobbered registers which are live across a call.
    Copyright (C) 1989, 1992, 1994, 1995, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -29,37 +30,24 @@ along with GCC; see the file COPYING3.  If not see
 #include "hard-reg-set.h"
 #include "recog.h"
 #include "basic-block.h"
+#include "df.h"
 #include "reload.h"
 #include "function.h"
 #include "expr.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "tm_p.h"
 #include "addresses.h"
 #include "output.h"
-#include "df.h"
 #include "ggc.h"
 
-/* Call used hard registers which can not be saved because there is no
-   insn for this.  */
-HARD_REG_SET no_caller_save_reg_set;
-
-#ifndef MAX_MOVE_MAX
-#define MAX_MOVE_MAX MOVE_MAX
-#endif
-
-#ifndef MIN_UNITS_PER_WORD
-#define MIN_UNITS_PER_WORD UNITS_PER_WORD
-#endif
-
 #define MOVE_MAX_WORDS (MOVE_MAX / UNITS_PER_WORD)
 
-/* Modes for each hard register that we can save.  The smallest mode is wide
-   enough to save the entire contents of the register.  When saving the
-   register because it is live we first try to save in multi-register modes.
-   If that is not possible the save is done one register at a time.  */
-
-static enum machine_mode
-  regno_save_mode[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
+#define regno_save_mode \
+  (this_target_reload->x_regno_save_mode)
+#define cached_reg_save_code \
+  (this_target_reload->x_cached_reg_save_code)
+#define cached_reg_restore_code \
+  (this_target_reload->x_cached_reg_restore_code)
 
 /* For each hard register, a place on the stack where it can be saved,
    if needed.  */
@@ -73,17 +61,6 @@ static int save_slots_num;
 /* Allocated slots so far.  */
 static rtx save_slots[FIRST_PSEUDO_REGISTER];
 
-/* We will only make a register eligible for caller-save if it can be
-   saved in its widest mode with a simple SET insn as long as the memory
-   address is valid.  We record the INSN_CODE is those insns here since
-   when we emit them, the addresses might not be valid, so they might not
-   be recognized.  */
-
-static int
-  cached_reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
-static int
-  cached_reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
-
 /* Set of hard regs currently residing in save area (during insn scan).  */
 
 static HARD_REG_SET hard_regs_saved;
@@ -97,18 +74,22 @@ static int n_regs_saved;
 static HARD_REG_SET referenced_regs;
 
 
+typedef void refmarker_fn (rtx *loc, enum machine_mode mode, int hardregno,
+                          void *mark_arg);
+
 static int reg_save_code (int, enum machine_mode);
 static int reg_restore_code (int, enum machine_mode);
 
 struct saved_hard_reg;
 static void initiate_saved_hard_regs (void);
-static struct saved_hard_reg *new_saved_hard_reg (int, int);
+static void new_saved_hard_reg (int, int);
 static void finish_saved_hard_regs (void);
 static int saved_hard_reg_compare_func (const void *, const void *);
 
 static void mark_set_regs (rtx, const_rtx, void *);
-static void add_stored_regs (rtx, const_rtx, void *);
-static void mark_referenced_regs (rtx);
+static void mark_referenced_regs (rtx *, refmarker_fn *mark, void *mark_arg);
+static refmarker_fn mark_reg_as_referenced;
+static refmarker_fn replace_reg_with_saved_mem;
 static int insert_save (struct insn_chain *, int, int, HARD_REG_SET *,
                        enum machine_mode *);
 static int insert_restore (struct insn_chain *, int, int, int,
@@ -134,15 +115,19 @@ reg_save_code (int reg, enum machine_mode mode)
   if (cached_reg_save_code[reg][mode])
      return cached_reg_save_code[reg][mode];
   if (!HARD_REGNO_MODE_OK (reg, mode))
-     {
-       cached_reg_save_code[reg][mode] = -1;
-       cached_reg_restore_code[reg][mode] = -1;
-       return -1;
-     }
+    {
+      /* Depending on how HARD_REGNO_MODE_OK is defined, range propagation
+        might deduce here that reg >= FIRST_PSEUDO_REGISTER.  So the assert
+        below silences a warning.  */
+      gcc_assert (reg < FIRST_PSEUDO_REGISTER);
+      cached_reg_save_code[reg][mode] = -1;
+      cached_reg_restore_code[reg][mode] = -1;
+      return -1;
+    }
 
   /* Update the register number and modes of the register
      and memory operand.  */
-  SET_REGNO (test_reg, reg);
+  SET_REGNO_RAW (test_reg, reg);
   PUT_MODE (test_reg, mode);
   PUT_MODE (test_mem, mode);
 
@@ -188,7 +173,7 @@ reg_restore_code (int reg, enum machine_mode mode)
 /* Initialize for caller-save.
 
    Look at all the hard registers that are used by a call and for which
-   regclass.c has not already excluded from being used across a call.
+   reginfo.c has not already excluded from being used across a call.
 
    Ensure that we can find a mode to save the register and that there is a
    simple insn to save and restore the register.  This latter check avoids
@@ -203,6 +188,11 @@ init_caller_save (void)
   rtx address;
   int i, j;
 
+  if (caller_save_initialized_p)
+    return;
+
+  caller_save_initialized_p = true;
+
   CLEAR_HARD_REG_SET (no_caller_save_reg_set);
   /* First find all the registers that we need to deal with and all
      the modes that they can have.  If we can't find a mode to use,
@@ -210,7 +200,8 @@ init_caller_save (void)
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      if (call_used_regs[i] && ! call_fixed_regs[i])
+      if (call_used_regs[i]
+          && !TEST_HARD_REG_BIT (call_fixed_reg_set, i))
        {
          for (j = 1; j <= MOVE_MAX_WORDS; j++)
            {
@@ -218,7 +209,6 @@ init_caller_save (void)
                                                                   VOIDmode);
              if (regno_save_mode[i][j] == VOIDmode && j == 1)
                {
-                 call_fixed_regs[i] = 1;
                  SET_HARD_REG_BIT (call_fixed_reg_set, i);
                }
            }
@@ -241,7 +231,8 @@ init_caller_save (void)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (TEST_HARD_REG_BIT
        (reg_class_contents
-        [(int) base_reg_class (regno_save_mode[i][1], PLUS, CONST_INT)], i))
+        [(int) base_reg_class (regno_save_mode[i][1], ADDR_SPACE_GENERIC,
+                               PLUS, CONST_INT)], i))
       break;
 
   gcc_assert (i < FIRST_PSEUDO_REGISTER);
@@ -276,8 +267,8 @@ init_caller_save (void)
   savepat = gen_rtx_SET (VOIDmode, test_mem, test_reg);
   restpat = gen_rtx_SET (VOIDmode, test_reg, test_mem);
 
-  saveinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, 0, 0, savepat, -1, 0);
-  restinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, 0, 0, restpat, -1, 0);
+  saveinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, 0, savepat, 0, -1, 0);
+  restinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, 0, restpat, 0, -1, 0);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     for (j = 1; j <= MOVE_MAX_WORDS; j++)
@@ -286,7 +277,6 @@ init_caller_save (void)
          regno_save_mode[i][j] = VOIDmode;
          if (j == 1)
            {
-             call_fixed_regs[i] = 1;
              SET_HARD_REG_BIT (call_fixed_reg_set, i);
              if (call_used_regs[i])
                SET_HARD_REG_BIT (no_caller_save_reg_set, i);
@@ -307,7 +297,7 @@ init_save_areas (void)
     for (j = 1; j <= MOVE_MAX_WORDS; j++)
       regno_save_mem[i][j] = 0;
   save_slots_num = 0;
-    
+
 }
 
 /* The structure represents a hard register which should be saved
@@ -357,7 +347,7 @@ initiate_saved_hard_regs (void)
 
 /* Allocate and return new saved hard register with given REGNO and
    CALL_FREQ.  */
-static struct saved_hard_reg *
+static void
 new_saved_hard_reg (int regno, int call_freq)
 {
   struct saved_hard_reg *saved_reg;
@@ -370,7 +360,6 @@ new_saved_hard_reg (int regno, int call_freq)
   saved_reg->call_freq = call_freq;
   saved_reg->first_p = FALSE;
   saved_reg->next = -1;
-  return saved_reg;
 }
 
 /* Free memory allocated for the saved hard registers.  */
@@ -390,7 +379,7 @@ saved_hard_reg_compare_func (const void *v1p, const void *v2p)
 {
   const struct saved_hard_reg *p1 = *(struct saved_hard_reg * const *) v1p;
   const struct saved_hard_reg *p2 = *(struct saved_hard_reg * const *) v2p;
-  
+
   if (flag_omit_frame_pointer)
     {
       if (p1->call_freq - p2->call_freq != 0)
@@ -427,101 +416,93 @@ saved_hard_reg_compare_func (const void *v1p, const void *v2p)
 void
 setup_save_areas (void)
 {
-  int i, j, k;
-  unsigned int r;
+  int i, j, k, freq;
   HARD_REG_SET hard_regs_used;
+  struct saved_hard_reg *saved_reg;
+  rtx insn;
+  struct insn_chain *chain, *next;
+  unsigned int regno;
+  HARD_REG_SET hard_regs_to_save, used_regs, this_insn_sets;
+  reg_set_iterator rsi;
 
-  /* Allocate space in the save area for the largest multi-register
-     pseudos first, then work backwards to single register
-     pseudos.  */
-
-  /* Find and record all call-used hard-registers in this function.  */
   CLEAR_HARD_REG_SET (hard_regs_used);
-  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-    if (reg_renumber[i] >= 0 && REG_N_CALLS_CROSSED (i) > 0)
-      {
-       unsigned int regno = reg_renumber[i];
-       unsigned int endregno
-         = end_hard_regno (GET_MODE (regno_reg_rtx[i]), regno);
-       for (r = regno; r < endregno; r++)
-         if (call_used_regs[r])
-           SET_HARD_REG_BIT (hard_regs_used, r);
-      }
-
-  if (flag_ira && optimize && flag_ira_share_save_slots)
+
+  /* Find every CALL_INSN and record which hard regs are live across the
+     call into HARD_REG_MAP and HARD_REGS_USED.  */
+  initiate_saved_hard_regs ();
+  /* Create hard reg saved regs.  */
+  for (chain = reload_insn_chain; chain != 0; chain = next)
     {
-      rtx insn, slot;
-      struct insn_chain *chain, *next;
-      char *saved_reg_conflicts;
-      unsigned int regno;
-      int next_k, freq;
-      struct saved_hard_reg *saved_reg, *saved_reg2, *saved_reg3;
-      int call_saved_regs_num;
-      struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER];
-      HARD_REG_SET hard_regs_to_save, used_regs, this_insn_sets;
-      reg_set_iterator rsi;
-      int best_slot_num;
-      int prev_save_slots_num;
-      rtx prev_save_slots[FIRST_PSEUDO_REGISTER];
-      
-      initiate_saved_hard_regs ();
-      /* Create hard reg saved regs.  */
-      for (chain = reload_insn_chain; chain != 0; chain = next)
+      insn = chain->insn;
+      next = chain->next;
+      if (!CALL_P (insn)
+         || find_reg_note (insn, REG_NORETURN, NULL))
+       continue;
+      freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
+      REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
+                              &chain->live_throughout);
+      COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+
+      /* Record all registers set in this call insn.  These don't
+        need to be saved.  N.B. the call insn might set a subreg
+        of a multi-hard-reg pseudo; then the pseudo is considered
+        live during the call, but the subreg that is set
+        isn't.  */
+      CLEAR_HARD_REG_SET (this_insn_sets);
+      note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+      /* Sibcalls are considered to set the return value.  */
+      if (SIBLING_CALL_P (insn) && crtl->return_rtx)
+       mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
+
+      AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
+      AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
+      AND_HARD_REG_SET (hard_regs_to_save, used_regs);
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+         {
+           if (hard_reg_map[regno] != NULL)
+             hard_reg_map[regno]->call_freq += freq;
+           else
+             new_saved_hard_reg (regno, freq);
+           SET_HARD_REG_BIT (hard_regs_used, regno);
+         }
+      /* Look through all live pseudos, mark their hard registers.  */
+      EXECUTE_IF_SET_IN_REG_SET
+       (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
        {
-         insn = chain->insn;
-         next = chain->next;
-         if (GET_CODE (insn) != CALL_INSN
-             || find_reg_note (insn, REG_NORETURN, NULL))
-           continue;
-         freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
-         REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
-                                  &chain->live_throughout);
-         COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+         int r = reg_renumber[regno];
+         int bound;
 
-         /* Record all registers set in this call insn.  These don't
-            need to be saved.  N.B. the call insn might set a subreg
-            of a multi-hard-reg pseudo; then the pseudo is considered
-            live during the call, but the subreg that is set
-            isn't.  */
-         CLEAR_HARD_REG_SET (this_insn_sets);
-         note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
-         /* Sibcalls are considered to set the return value.  */
-         if (SIBLING_CALL_P (insn) && crtl->return_rtx)
-           mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
+         if (r < 0)
+           continue;
 
-         AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
-         AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
-         AND_HARD_REG_SET (hard_regs_to_save, used_regs);
-         for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-           if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+         bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+         for (; r < bound; r++)
+           if (TEST_HARD_REG_BIT (used_regs, r))
              {
-               if (hard_reg_map[regno] != NULL)
-                 hard_reg_map[regno]->call_freq += freq;
+               if (hard_reg_map[r] != NULL)
+                 hard_reg_map[r]->call_freq += freq;
                else
-                 saved_reg = new_saved_hard_reg (regno, freq);
+                 new_saved_hard_reg (r, freq);
+                SET_HARD_REG_BIT (hard_regs_to_save, r);
+                SET_HARD_REG_BIT (hard_regs_used, r);
              }
-         /* Look through all live pseudos, mark their hard registers.  */
-         EXECUTE_IF_SET_IN_REG_SET
-           (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
-           {
-             int r = reg_renumber[regno];
-             int bound;
-             
-             if (r < 0)
-               continue;
-             
-             bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
-             for (; r < bound; r++)
-               if (TEST_HARD_REG_BIT (used_regs, r))
-                 {
-                   if (hard_reg_map[r] != NULL)
-                     hard_reg_map[r]->call_freq += freq;
-                   else
-                     saved_reg = new_saved_hard_reg (r, freq);
-                   SET_HARD_REG_BIT (hard_regs_to_save, r);
-                 }
-           }
        }
+    }
+
+  /* If requested, figure out which hard regs can share save slots.  */
+  if (optimize && flag_ira_share_save_slots)
+    {
+      rtx slot;
+      char *saved_reg_conflicts;
+      int next_k;
+      struct saved_hard_reg *saved_reg2, *saved_reg3;
+      int call_saved_regs_num;
+      struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER];
+      int best_slot_num;
+      int prev_save_slots_num;
+      rtx prev_save_slots[FIRST_PSEUDO_REGISTER];
+
       /* Find saved hard register conflicts.  */
       saved_reg_conflicts = (char *) xmalloc (saved_regs_num * saved_regs_num);
       memset (saved_reg_conflicts, 0, saved_regs_num * saved_regs_num);
@@ -530,7 +511,7 @@ setup_save_areas (void)
          call_saved_regs_num = 0;
          insn = chain->insn;
          next = chain->next;
-         if (GET_CODE (insn) != CALL_INSN
+         if (!CALL_P (insn)
              || find_reg_note (insn, REG_NORETURN, NULL))
            continue;
          REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
@@ -545,7 +526,7 @@ setup_save_areas (void)
          CLEAR_HARD_REG_SET (this_insn_sets);
          note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
          /* Sibcalls are considered to set the return value,
-            compare flow.c:propagate_one_insn.  */
+            compare df-scan.c:df_get_call_refs.  */
          if (SIBLING_CALL_P (insn) && crtl->return_rtx)
            mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
 
@@ -564,7 +545,7 @@ setup_save_areas (void)
            {
              int r = reg_renumber[regno];
              int bound;
-             
+
              if (r < 0)
                continue;
 
@@ -666,7 +647,8 @@ setup_save_areas (void)
                  saved_reg->slot
                    = assign_stack_local_1
                      (regno_save_mode[regno][1],
-                      GET_MODE_SIZE (regno_save_mode[regno][1]), 0, true);
+                      GET_MODE_SIZE (regno_save_mode[regno][1]), 0,
+                      ASLK_REDUCE_ALIGN);
                  if (dump_file != NULL)
                    fprintf (dump_file, "%d uses a new slot\n", regno);
                }
@@ -679,20 +661,22 @@ setup_save_areas (void)
     }
   else
     {
-      /* Now run through all the call-used hard-registers and allocate
-        space for them in the caller-save area.  Try to allocate space
+      /* We are not sharing slots. 
+
+        Run through all the call-used hard-registers and allocate
+        space for each in the caller-save area.  Try to allocate space
         in a manner which allows multi-register saves/restores to be done.  */
-      
+
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        for (j = MOVE_MAX_WORDS; j > 0; j--)
          {
            int do_save = 1;
-           
+
            /* If no mode exists for this size, try another.  Also break out
               if we have already saved this hard register.  */
            if (regno_save_mode[i][j] == VOIDmode || regno_save_mem[i][1] != 0)
              continue;
-           
+
            /* See if any register in this group has been saved.  */
            for (k = 0; k < j; k++)
              if (regno_save_mem[i + k][1])
@@ -702,7 +686,7 @@ setup_save_areas (void)
                }
            if (! do_save)
              continue;
-           
+
            for (k = 0; k < j; k++)
              if (! TEST_HARD_REG_BIT (hard_regs_used, i + k))
                {
@@ -711,7 +695,7 @@ setup_save_areas (void)
                }
            if (! do_save)
              continue;
-           
+
            /* We have found an acceptable mode to store in.  Since
               hard register is always saved in the widest mode
               available, the mode may be wider than necessary, it is
@@ -722,8 +706,8 @@ setup_save_areas (void)
            regno_save_mem[i][j]
              = assign_stack_local_1 (regno_save_mode[i][j],
                                      GET_MODE_SIZE (regno_save_mode[i][j]),
-                                     0, true);
-           
+                                     0, ASLK_REDUCE_ALIGN);
+
            /* Setup single word save area just in case...  */
            for (k = 0; k < j; k++)
              /* This should not depend on WORDS_BIG_ENDIAN.
@@ -750,7 +734,7 @@ setup_save_areas (void)
 void
 save_call_clobbered_regs (void)
 {
-  struct insn_chain *chain, *next;
+  struct insn_chain *chain, *next, *last = NULL;
   enum machine_mode save_mode [FIRST_PSEUDO_REGISTER];
 
   /* Computed in mark_set_regs, holds all registers set by the current
@@ -769,7 +753,7 @@ save_call_clobbered_regs (void)
 
       gcc_assert (!chain->is_caller_save_insn);
 
-      if (INSN_P (insn))
+      if (NONDEBUG_INSN_P (insn))
        {
          /* If some registers have been saved, see if INSN references
             any of them.  We must restore them before the insn if so.  */
@@ -777,6 +761,7 @@ save_call_clobbered_regs (void)
          if (n_regs_saved)
            {
              int regno;
+             HARD_REG_SET this_insn_sets;
 
              if (code == JUMP_INSN)
                /* Restore all registers if this is a JUMP_INSN.  */
@@ -784,13 +769,24 @@ save_call_clobbered_regs (void)
              else
                {
                  CLEAR_HARD_REG_SET (referenced_regs);
-                 mark_referenced_regs (PATTERN (insn));
+                 mark_referenced_regs (&PATTERN (insn),
+                                       mark_reg_as_referenced, NULL);
                  AND_HARD_REG_SET (referenced_regs, hard_regs_saved);
                }
 
              for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
                if (TEST_HARD_REG_BIT (referenced_regs, regno))
-                 regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS, save_mode);
+                 regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS,
+                                          save_mode);
+             /* If a saved register is set after the call, this means we no
+                longer should restore it.  This can happen when parts of a
+                multi-word pseudo do not conflict with other pseudos, so
+                IRA may allocate the same hard register for both.  One may
+                be live across the call, while the other is set
+                afterwards.  */
+             CLEAR_HARD_REG_SET (this_insn_sets);
+             note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+             AND_COMPL_HARD_REG_SET (hard_regs_saved, this_insn_sets);
            }
 
          if (code == CALL_INSN
@@ -856,7 +852,12 @@ save_call_clobbered_regs (void)
                if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
                  n_regs_saved++;
            }
+          last = chain;
        }
+      else if (DEBUG_INSN_P (insn) && n_regs_saved)
+       mark_referenced_regs (&PATTERN (insn),
+                             replace_reg_with_saved_mem,
+                             save_mode);
 
       if (chain->next == 0 || chain->next->block != chain->block)
        {
@@ -865,6 +866,39 @@ save_call_clobbered_regs (void)
             remain saved.  If the last insn in the block is a JUMP_INSN, put
             the restore before the insn, otherwise, put it after the insn.  */
 
+         if (n_regs_saved
+             && DEBUG_INSN_P (insn)
+             && last
+             && last->block == chain->block)
+           {
+             rtx ins, prev;
+             basic_block bb = BLOCK_FOR_INSN (insn);
+
+             /* When adding hard reg restores after a DEBUG_INSN, move
+                all notes between last real insn and this DEBUG_INSN after
+                the DEBUG_INSN, otherwise we could get code
+                -g/-g0 differences.  */
+             for (ins = PREV_INSN (insn); ins != last->insn; ins = prev)
+               {
+                 prev = PREV_INSN (ins);
+                 if (NOTE_P (ins))
+                   {
+                     NEXT_INSN (prev) = NEXT_INSN (ins);
+                     PREV_INSN (NEXT_INSN (ins)) = prev;
+                     PREV_INSN (ins) = insn;
+                     NEXT_INSN (ins) = NEXT_INSN (insn);
+                     NEXT_INSN (insn) = ins;
+                     if (NEXT_INSN (ins))
+                       PREV_INSN (NEXT_INSN (ins)) = ins;
+                      if (BB_END (bb) == insn)
+                       BB_END (bb) = ins;
+                   }
+                 else
+                   gcc_assert (DEBUG_INSN_P (ins));
+               }
+           }
+         last = NULL;
+
          if (n_regs_saved)
            for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
              if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
@@ -946,52 +980,57 @@ add_stored_regs (rtx reg, const_rtx setter, void *data)
 
 /* Walk X and record all referenced registers in REFERENCED_REGS.  */
 static void
-mark_referenced_regs (rtx x)
+mark_referenced_regs (rtx *loc, refmarker_fn *mark, void *arg)
 {
-  enum rtx_code code = GET_CODE (x);
+  enum rtx_code code = GET_CODE (*loc);
   const char *fmt;
   int i, j;
 
   if (code == SET)
-    mark_referenced_regs (SET_SRC (x));
+    mark_referenced_regs (&SET_SRC (*loc), mark, arg);
   if (code == SET || code == CLOBBER)
     {
-      x = SET_DEST (x);
-      code = GET_CODE (x);
-      if ((code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+      loc = &SET_DEST (*loc);
+      code = GET_CODE (*loc);
+      if ((code == REG && REGNO (*loc) < FIRST_PSEUDO_REGISTER)
          || code == PC || code == CC0
-         || (code == SUBREG && REG_P (SUBREG_REG (x))
-             && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
+         || (code == SUBREG && REG_P (SUBREG_REG (*loc))
+             && REGNO (SUBREG_REG (*loc)) < FIRST_PSEUDO_REGISTER
              /* If we're setting only part of a multi-word register,
                 we shall mark it as referenced, because the words
                 that are not being set should be restored.  */
-             && ((GET_MODE_SIZE (GET_MODE (x))
-                  >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-                 || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+             && ((GET_MODE_SIZE (GET_MODE (*loc))
+                  >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (*loc))))
+                 || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (*loc)))
                      <= UNITS_PER_WORD))))
        return;
     }
   if (code == MEM || code == SUBREG)
     {
-      x = XEXP (x, 0);
-      code = GET_CODE (x);
+      loc = &XEXP (*loc, 0);
+      code = GET_CODE (*loc);
     }
 
   if (code == REG)
     {
-      int regno = REGNO (x);
+      int regno = REGNO (*loc);
       int hardregno = (regno < FIRST_PSEUDO_REGISTER ? regno
                       : reg_renumber[regno]);
 
       if (hardregno >= 0)
-       add_to_hard_reg_set (&referenced_regs, GET_MODE (x), hardregno);
+       mark (loc, GET_MODE (*loc), hardregno, arg);
+      else if (arg)
+       /* ??? Will we ever end up with an equiv expression in a debug
+          insn, that would have required restoring a reg, or will
+          reload take care of it for us?  */
+       return;
       /* If this is a pseudo that did not get a hard register, scan its
         memory location, since it might involve the use of another
         register, which might be saved.  */
-      else if (reg_equiv_mem[regno] != 0)
-       mark_referenced_regs (XEXP (reg_equiv_mem[regno], 0));
-      else if (reg_equiv_address[regno] != 0)
-       mark_referenced_regs (reg_equiv_address[regno]);
+      else if (reg_equiv_mem (regno) != 0)
+       mark_referenced_regs (&XEXP (reg_equiv_mem (regno), 0), mark, arg);
+      else if (reg_equiv_address (regno) != 0)
+       mark_referenced_regs (&reg_equiv_address (regno), mark, arg);
       return;
     }
 
@@ -999,12 +1038,100 @@ mark_referenced_regs (rtx x)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       mark_referenced_regs (XEXP (x, i));
+       mark_referenced_regs (&XEXP (*loc, i), mark, arg);
       else if (fmt[i] == 'E')
-       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         mark_referenced_regs (XVECEXP (x, i, j));
+       for (j = XVECLEN (*loc, i) - 1; j >= 0; j--)
+         mark_referenced_regs (&XVECEXP (*loc, i, j), mark, arg);
     }
 }
+
+/* Parameter function for mark_referenced_regs() that adds registers
+   present in the insn and in equivalent mems and addresses to
+   referenced_regs.  */
+
+static void
+mark_reg_as_referenced (rtx *loc ATTRIBUTE_UNUSED,
+                       enum machine_mode mode,
+                       int hardregno,
+                       void *arg ATTRIBUTE_UNUSED)
+{
+  add_to_hard_reg_set (&referenced_regs, mode, hardregno);
+}
+
+/* Parameter function for mark_referenced_regs() that replaces
+   registers referenced in a debug_insn that would have been restored,
+   should it be a non-debug_insn, with their save locations.  */
+
+static void
+replace_reg_with_saved_mem (rtx *loc,
+                           enum machine_mode mode,
+                           int regno,
+                           void *arg)
+{
+  unsigned int i, nregs = hard_regno_nregs [regno][mode];
+  rtx mem;
+  enum machine_mode *save_mode = (enum machine_mode *)arg;
+
+  for (i = 0; i < nregs; i++)
+    if (TEST_HARD_REG_BIT (hard_regs_saved, regno + i))
+      break;
+
+  /* If none of the registers in the range would need restoring, we're
+     all set.  */
+  if (i == nregs)
+    return;
+
+  while (++i < nregs)
+    if (!TEST_HARD_REG_BIT (hard_regs_saved, regno + i))
+      break;
+
+  if (i == nregs
+      && regno_save_mem[regno][nregs])
+    {
+      mem = copy_rtx (regno_save_mem[regno][nregs]);
+
+      if (nregs == (unsigned int) hard_regno_nregs[regno][save_mode[regno]])
+       mem = adjust_address_nv (mem, save_mode[regno], 0);
+
+      if (GET_MODE (mem) != mode)
+       {
+         /* This is gen_lowpart_if_possible(), but without validating
+            the newly-formed address.  */
+         int offset = 0;
+
+         if (WORDS_BIG_ENDIAN)
+           offset = (MAX (GET_MODE_SIZE (GET_MODE (mem)), UNITS_PER_WORD)
+                     - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
+         if (BYTES_BIG_ENDIAN)
+           /* Adjust the address so that the address-after-the-data is
+              unchanged.  */
+           offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
+                      - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (mem))));
+
+         mem = adjust_address_nv (mem, mode, offset);
+       }
+    }
+  else
+    {
+      mem = gen_rtx_CONCATN (mode, rtvec_alloc (nregs));
+      for (i = 0; i < nregs; i++)
+       if (TEST_HARD_REG_BIT (hard_regs_saved, regno + i))
+         {
+           gcc_assert (regno_save_mem[regno + i][1]);
+           XVECEXP (mem, 0, i) = copy_rtx (regno_save_mem[regno + i][1]);
+         }
+       else
+         {
+           gcc_assert (save_mode[regno] != VOIDmode);
+           XVECEXP (mem, 0, i) = gen_rtx_REG (save_mode [regno],
+                                              regno + i);
+         }
+    }
+
+  gcc_assert (GET_MODE (mem) == mode);
+  *loc = mem;
+}
+
 \f
 /* Insert a sequence of insns to restore.  Place these insns in front of
    CHAIN if BEFORE_P is nonzero, behind the insn otherwise.  MAXRESTORE is
@@ -1071,7 +1198,7 @@ insert_restore (struct insn_chain *chain, int before_p, int regno,
       /* Check that insn to restore REGNO in save_mode[regno] is
         correct.  */
       && reg_save_code (regno, save_mode[regno]) >= 0)
-    mem = adjust_address (mem, save_mode[regno], 0);
+    mem = adjust_address_nv (mem, save_mode[regno], 0);
   else
     mem = copy_rtx (mem);
 
@@ -1152,7 +1279,7 @@ insert_save (struct insn_chain *chain, int before_p, int regno,
       /* Check that insn to save REGNO in save_mode[regno] is
         correct.  */
       && reg_save_code (regno, save_mode[regno]) >= 0)
-    mem = adjust_address (mem, save_mode[regno], 0);
+    mem = adjust_address_nv (mem, save_mode[regno], 0);
   else
     mem = copy_rtx (mem);
 
@@ -1179,6 +1306,38 @@ insert_save (struct insn_chain *chain, int before_p, int regno,
   return numregs - 1;
 }
 
+/* A for_each_rtx callback used by add_used_regs.  Add the hard-register
+   equivalent of each REG to regset DATA.  */
+
+static int
+add_used_regs_1 (rtx *loc, void *data)
+{
+  unsigned int regno;
+  regset live;
+  rtx x;
+
+  x = *loc;
+  live = (regset) data;
+  if (REG_P (x))
+    {
+      regno = REGNO (x);
+      if (HARD_REGISTER_NUM_P (regno))
+       bitmap_set_range (live, regno, hard_regno_nregs[regno][GET_MODE (x)]);
+      else
+       regno = reg_renumber[regno];
+    }
+  return 0;
+}
+
+/* A note_uses callback used by insert_one_insn.  Add the hard-register
+   equivalent of each REG to regset DATA.  */
+
+static void
+add_used_regs (rtx *loc, void *data)
+{
+  for_each_rtx (loc, add_used_regs_1, data);
+}
+
 /* Emit a new caller-save insn and set the code.  */
 static struct insn_chain *
 insert_one_insn (struct insn_chain *chain, int before_p, int code, rtx pat)
@@ -1216,56 +1375,16 @@ insert_one_insn (struct insn_chain *chain, int before_p, int code, rtx pat)
       /* ??? It would be nice if we could exclude the already / still saved
         registers from the live sets.  */
       COPY_REG_SET (&new_chain->live_throughout, &chain->live_throughout);
-      /* Registers that die in CHAIN->INSN still live in the new insn.  */
-      for (link = REG_NOTES (chain->insn); link; link = XEXP (link, 1))
-       {
-         if (REG_NOTE_KIND (link) == REG_DEAD)
-           {
-             rtx reg = XEXP (link, 0);
-             int regno, i;
-
-             gcc_assert (REG_P (reg));
-             regno = REGNO (reg);
-             if (regno >= FIRST_PSEUDO_REGISTER)
-               regno = reg_renumber[regno];
-             if (regno < 0)
-               continue;
-             for (i = hard_regno_nregs[regno][GET_MODE (reg)] - 1;
-                  i >= 0; i--)
-               SET_REGNO_REG_SET (&new_chain->live_throughout, regno + i);
-           }
-       }
-
+      note_uses (&PATTERN (chain->insn), add_used_regs,
+                &new_chain->live_throughout);
       /* If CHAIN->INSN is a call, then the registers which contain
         the arguments to the function are live in the new insn.  */
       if (CALL_P (chain->insn))
-       {
-         for (link = CALL_INSN_FUNCTION_USAGE (chain->insn);
-              link != NULL_RTX;
-              link = XEXP (link, 1))
-           {
-             rtx arg = XEXP (link, 0);
-
-             if (GET_CODE (arg) == USE)
-               {
-                 rtx reg = XEXP (arg, 0);
-
-                 if (REG_P (reg))
-                   {
-                     int i, regno = REGNO (reg);
-
-                     /* Registers in CALL_INSN_FUNCTION_USAGE are always
-                        hard registers.  */
-                     gcc_assert (regno < FIRST_PSEUDO_REGISTER);
-
-                     for (i = hard_regno_nregs[regno][GET_MODE (reg)] - 1;
-                          i >= 0; i--)
-                       SET_REGNO_REG_SET (&new_chain->live_throughout, regno + i);
-                   }
-               }
-           }
-         
-       }
+       for (link = CALL_INSN_FUNCTION_USAGE (chain->insn);
+            link != NULL_RTX;
+            link = XEXP (link, 1))
+         note_uses (&XEXP (link, 0), add_used_regs,
+                    &new_chain->live_throughout);
 
       CLEAR_REG_SET (&new_chain->dead_or_set);
       if (chain->insn == BB_HEAD (BASIC_BLOCK (chain->block)))