OSDN Git Service

91th Cygnus<->FSF merge
[pf3gnuchains/gcc-fork.git] / gcc / caller-save.c
index 3ecbd24..ea5923d 100644 (file)
@@ -1,5 +1,5 @@
 /* Save and restore call-clobbered registers which are live across a call.
-   Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1992, 1994, 1995, 1997 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 "config.h"
 #include "rtl.h"
@@ -28,19 +29,27 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "reload.h"
 #include "expr.h"
 
+#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
+
 /* 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][MOVE_MAX / UNITS_PER_WORD + 1];
+  regno_save_mode[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
 
 /* For each hard register, a place on the stack where it can be saved,
    if needed.  */
 
 static rtx 
-  regno_save_mem[FIRST_PSEUDO_REGISTER][MOVE_MAX / UNITS_PER_WORD + 1];
+  regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
 
 /* 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
@@ -49,9 +58,9 @@ static rtx
    be recognized.  */
 
 static enum insn_code 
-  reg_save_code[FIRST_PSEUDO_REGISTER][MOVE_MAX / UNITS_PER_WORD + 1];
+  reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
 static enum insn_code 
-  reg_restore_code[FIRST_PSEUDO_REGISTER][MOVE_MAX / UNITS_PER_WORD + 1];
+  reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
 
 /* Set of hard regs currently live (during scan of all insns).  */
 
@@ -69,49 +78,11 @@ static HARD_REG_SET hard_regs_need_restore;
 
 int n_regs_saved;
 
-static void set_reg_live ();
-static void clear_reg_live ();
-static void restore_referenced_regs ();
-static int insert_save_restore ();
-\f
-/* Return a machine mode that is legitimate for hard reg REGNO and large
-   enough to save nregs.  If we can't find one, return VOIDmode.  */
-
-static enum machine_mode
-choose_hard_reg_mode (regno, nregs)
-     int regno;
-{
-  enum machine_mode found_mode = VOIDmode, mode;
-
-  /* We first look for the largest integer mode that can be validly
-     held in REGNO.  If none, we look for the largest floating-point mode.
-     If we still didn't find a valid mode, try CCmode.  */
-
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
-       mode = GET_MODE_WIDER_MODE (mode))
-    if (HARD_REGNO_NREGS (regno, mode) == nregs
-       && HARD_REGNO_MODE_OK (regno, mode))
-      found_mode = mode;
-
-  if (found_mode != VOIDmode)
-    return found_mode;
-
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
-       mode = GET_MODE_WIDER_MODE (mode))
-    if (HARD_REGNO_NREGS (regno, mode) == nregs
-       && HARD_REGNO_MODE_OK (regno, mode))
-      found_mode = mode;
-
-  if (found_mode != VOIDmode)
-    return found_mode;
-
-  if (HARD_REGNO_NREGS (regno, CCmode) == nregs
-      && HARD_REGNO_MODE_OK (regno, CCmode))
-    return CCmode;
-
-  /* We can't find a mode valid for this register.  */
-  return VOIDmode;
-}
+static void set_reg_live               PROTO((rtx, rtx));
+static void clear_reg_live             PROTO((rtx));
+static void restore_referenced_regs    PROTO((rtx, rtx, enum machine_mode));
+static int insert_save_restore         PROTO((rtx, int, int,
+                                              enum machine_mode, int));
 \f
 /* Initialize for caller-save.
 
@@ -211,7 +182,8 @@ init_caller_save ()
          reg_save_code[i][j] = recog_memoized (saveinsn);
          reg_restore_code[i][j] = recog_memoized (restinsn);
 
-         /* Now extract both insns and see if we can meet their constraints. */
+         /* Now extract both insns and see if we can meet their
+             constraints.  */
          ok = (reg_save_code[i][j] != -1 && reg_restore_code[i][j] != -1);
          if (ok)
            {
@@ -336,7 +308,7 @@ setup_save_areas (pchanged)
              ok &= (TEST_HARD_REG_BIT (hard_regs_used, regno) != 0);
            }
 
-       /* We have found an acceptable mode to store in. */
+       /* We have found an acceptable mode to store in.  */
        if (ok)
          {
 
@@ -344,7 +316,7 @@ setup_save_areas (pchanged)
              = assign_stack_local (regno_save_mode[i][j],
                                    GET_MODE_SIZE (regno_save_mode[i][j]), 0);
 
-           /* Setup single word save area just in case... */
+           /* Setup single word save area just in case...  */
            for (k = 0; k < j; k++)
              {
                /* This should not depend on WORDS_BIG_ENDIAN.
@@ -363,7 +335,7 @@ setup_save_areas (pchanged)
     for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
       if (regno_save_mem[i][j] != 0)
        ok &= strict_memory_address_p (GET_MODE (regno_save_mem[i][j]),
-                                      XEXP (eliminate_regs (regno_save_mem[i][j], 0, NULL_RTX), 0));
+                                      XEXP (eliminate_regs (regno_save_mem[i][j], 0, NULL_RTX, 1), 0));
 
   return ok;
 }
@@ -454,32 +426,62 @@ save_call_clobbered_regs (insn_mode)
                 live, call-used, not fixed, and not already saved.  We must
                 test at this point because registers that die in a CALL_INSN
                 are not live across the call and likewise for registers that
-                are born in the CALL_INSN.  */
+                are born in the CALL_INSN.
+                
+                If registers are filled with parameters for this function,
+                and some of these are also being set by this function, then
+                they will not appear to die (no REG_DEAD note for them),
+                to check if in fact they do, collect the set registers in
+                hard_regs_live first.  */
 
              if (code == CALL_INSN)
                {
+                 HARD_REG_SET this_call_sets;
+                 {
+                   HARD_REG_SET old_hard_regs_live;
+
+                   /* Save the hard_regs_live information.  */
+                   COPY_HARD_REG_SET (old_hard_regs_live, hard_regs_live);
+
+                   /* Now calculate hard_regs_live for this CALL_INSN
+                      only.  */
+                   CLEAR_HARD_REG_SET (hard_regs_live);
+                   note_stores (PATTERN (insn), set_reg_live);
+                   COPY_HARD_REG_SET (this_call_sets, hard_regs_live);
+
+                   /* Restore the hard_regs_live information.  */
+                   COPY_HARD_REG_SET (hard_regs_live, old_hard_regs_live);
+                 }
+
                  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
                    if (call_used_regs[regno] && ! call_fixed_regs[regno]
                        && TEST_HARD_REG_BIT (hard_regs_live, regno)
+                       /* It must not be set by this instruction.  */
+                       && ! TEST_HARD_REG_BIT (this_call_sets, regno)
                        && ! TEST_HARD_REG_BIT (hard_regs_saved, regno))
                      regno += insert_save_restore (insn, 1, regno, 
                                                    insn_mode, 0);
-#ifdef HARD_REG_SET
-                 hard_regs_need_restore = hard_regs_saved;
-#else
-                 COPY_HARD_REG_SET (hard_regs_need_restore,
-                                    hard_regs_saved);
-#endif
+
+                 /* Put the information for this CALL_INSN on top of what
+                    we already had.  */
+                 IOR_HARD_REG_SET (hard_regs_live, this_call_sets);
+                 COPY_HARD_REG_SET (hard_regs_need_restore, hard_regs_saved);
 
                  /* Must recompute n_regs_saved.  */
                  n_regs_saved = 0;
                  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
                    if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
                      n_regs_saved++;
-                 
                }
-             
-             note_stores (PATTERN (insn), set_reg_live);
+             else
+               {
+                 note_stores (PATTERN (insn), set_reg_live);
+#ifdef AUTO_INC_DEC
+                 for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+                   if (REG_NOTE_KIND (link) == REG_INC)
+                     set_reg_live (XEXP (link, 0), NULL_RTX);
+#endif
+               }
 
              for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
                if (REG_NOTE_KIND (link) == REG_UNUSED)
@@ -602,13 +604,15 @@ restore_referenced_regs (x, insn, insn_mode)
 
       else if (regno < FIRST_PSEUDO_REGISTER)
        {
-         int numregs = MIN (HARD_REGNO_NREGS (regno, GET_MODE (x)),
-                            MOVE_MAX / UNITS_PER_WORD);
+         int numregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
+         /* Save at most SAVEREGS at a time.  This can not be larger than
+            MOVE_MAX, because that causes insert_save_restore to fail.  */
+         int saveregs = MIN (numregs, MOVE_MAX / UNITS_PER_WORD);
          int endregno = regno + numregs;
 
          for (i = regno; i < endregno; i++)
            if (TEST_HARD_REG_BIT (hard_regs_need_restore, i))
-             i += insert_save_restore (insn, 0, i, insn_mode, numregs);
+             i += insert_save_restore (insn, 0, i, insn_mode, saveregs);
        }
 
       return;
@@ -661,14 +665,6 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
   if (regno_save_mem[regno][1] == 0)
     abort ();
 
-  /* If INSN is a CALL_INSN, we must insert our insns before any
-     USE insns in front of the CALL_INSN.  */
-
-  if (GET_CODE (insn) == CALL_INSN)
-    while (GET_CODE (PREV_INSN (insn)) == INSN
-          && GET_CODE (PATTERN (PREV_INSN (insn))) == USE)
-      insn = PREV_INSN (insn);
-
 #ifdef HAVE_cc0
   /* If INSN references CC0, put our insns in front of the insn that sets
      CC0.  This is always safe, since the only way we could be passed an