OSDN Git Service

91th Cygnus<->FSF merge
[pf3gnuchains/gcc-fork.git] / gcc / caller-save.c
index cc356c3..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,7 +29,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "reload.h"
 #include "expr.h"
 
-#define CEIL(x,y) (((x) + (y) - 1) / (y))
+#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
@@ -36,13 +43,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    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
@@ -51,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).  */
 
@@ -71,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.
 
@@ -213,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)
            {
@@ -314,19 +284,31 @@ setup_save_areas (pchanged)
     for (j = MOVE_MAX / UNITS_PER_WORD; j > 0; j--)
       {
        int ok = 1;
+       int do_save;
 
        /* 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.  */
+       do_save = 1;
+       for (k = 0; k < j; k++)
+         if (regno_save_mem[i + k][1])
+           {
+             do_save = 0;
+             break;
+           }
+       if (! do_save)
+         continue;
+
        for (k = 0; k < j; k++)
            {
              int regno = i + k;
              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)
          {
 
@@ -334,22 +316,16 @@ setup_save_areas (pchanged)
              = assign_stack_local (regno_save_mode[i][j],
                                    GET_MODE_SIZE (regno_save_mode[i][j]), 0);
 
-           /* Setup singe word save area just in case... */
+           /* Setup single word save area just in case...  */
            for (k = 0; k < j; k++)
              {
-               int offset;
-               rtx temp;
+               /* This should not depend on WORDS_BIG_ENDIAN.
+                  The order of words in regs is the same as in memory.  */
+               rtx temp = gen_rtx (MEM, regno_save_mode[i+k][1], 
+                                   XEXP (regno_save_mem[i][j], 0));
 
-               if (WORDS_BIG_ENDIAN) 
-                 offset = k * UNITS_PER_WORD;
-               else
-                 offset =  - k * UNITS_PER_WORD;
-
-               temp 
-                 = gen_rtx(MEM, regno_save_mode[i+k][1], 
-                           XEXP (regno_save_mem[i][j], 0));
                regno_save_mem[i+k][1] 
-                 = adj_offsettable_operand(temp, offset);
+                 = adj_offsettable_operand (temp, k * UNITS_PER_WORD);
              }
            *pchanged = 1;
          }
@@ -359,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;
 }
@@ -380,6 +356,7 @@ save_call_clobbered_regs (insn_mode)
   for (b = 0; b < n_basic_blocks; b++)
     {
       regset regs_live = basic_block_live_at_start[b];
+      rtx prev_block_last = PREV_INSN (basic_block_head[b]);
       REGSET_ELT_TYPE bit;
       int offset, i, j;
       int regno;
@@ -449,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)
@@ -496,6 +503,9 @@ save_call_clobbered_regs (insn_mode)
                                  ? insn : NEXT_INSN (insn)), 0,
                                  regno, insn_mode, MOVE_MAX / UNITS_PER_WORD);
 
+      /* If we added any insns at the start of the block, update the start
+        of the block to point at those insns.  */
+      basic_block_head[b] = NEXT_INSN (prev_block_last);
     }
 }
 
@@ -594,12 +604,15 @@ restore_referenced_regs (x, insn, insn_mode)
 
       else if (regno < FIRST_PSEUDO_REGISTER)
        {
-         int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+         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, 
-                  CEIL (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD));
+             i += insert_save_restore (insn, 0, i, insn_mode, saveregs);
        }
 
       return;
@@ -652,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