OSDN Git Service

* config/i386/rtemself.h: Updated to keep in sync with
[pf3gnuchains/gcc-fork.git] / gcc / caller-save.c
index 3518feb..4a2deb6 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, 94-95, 1997, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,9 +15,11 @@ 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 "system.h"
 #include "rtl.h"
 #include "insn-config.h"
 #include "flags.h"
@@ -27,13 +29,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "basic-block.h"
 #include "reload.h"
 #include "expr.h"
+#include "toplev.h"
 
 #ifndef MAX_MOVE_MAX
 #define MAX_MOVE_MAX MOVE_MAX
 #endif
 
-#ifndef MAX_UNITS_PER_WORD
-#define MAX_UNITS_PER_WORD UNITS_PER_WORD
+#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
@@ -42,13 +45,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][MAX_MOVE_MAX / 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][MAX_MOVE_MAX / 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
@@ -57,9 +60,9 @@ static rtx
    be recognized.  */
 
 static enum insn_code 
-  reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / 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][MAX_MOVE_MAX / 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).  */
 
@@ -77,53 +80,12 @@ static HARD_REG_SET hard_regs_need_restore;
 
 int n_regs_saved;
 
-static enum machine_mode choose_hard_reg_mode PROTO((int, int));
 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
-/* 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;
-     int nregs;
-{
-  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;
-}
-\f
 /* Initialize for caller-save.
 
    Look at all the hard registers that are used by a call and for which
@@ -183,11 +145,11 @@ init_caller_save ()
   if (i == FIRST_PSEUDO_REGISTER)
     abort ();
 
-  addr_reg = gen_rtx (REG, Pmode, i);
+  addr_reg = gen_rtx_REG (Pmode, i);
 
   for (offset = 1 << (HOST_BITS_PER_INT / 2); offset; offset >>= 1)
     {
-      address = gen_rtx (PLUS, Pmode, addr_reg, GEN_INT (offset));
+      address = gen_rtx_PLUS (Pmode, addr_reg, GEN_INT (offset));
 
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (regno_save_mode[i][1] != VOIDmode
@@ -211,10 +173,10 @@ init_caller_save ()
     for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
       if (regno_save_mode[i][j] != VOIDmode)
         {
-         rtx mem = gen_rtx (MEM, regno_save_mode[i][j], address);
-         rtx reg = gen_rtx (REG, regno_save_mode[i][j], i);
-         rtx savepat = gen_rtx (SET, VOIDmode, mem, reg);
-         rtx restpat = gen_rtx (SET, VOIDmode, reg, mem);
+         rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address);
+         rtx reg = gen_rtx_REG (regno_save_mode[i][j], i);
+         rtx savepat = gen_rtx_SET (VOIDmode, mem, reg);
+         rtx restpat = gen_rtx_SET (VOIDmode, reg, mem);
          rtx saveinsn = emit_insn (savepat);
          rtx restinsn = emit_insn (restpat);
          int ok;
@@ -222,7 +184,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)
            {
@@ -301,7 +264,7 @@ setup_save_areas (pchanged)
   /* 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)
+    if (reg_renumber[i] >= 0 && REG_N_CALLS_CROSSED (i) > 0)
       {
        int regno = reg_renumber[i];
        int endregno 
@@ -347,7 +310,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)
          {
 
@@ -355,13 +318,13 @@ 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.
                   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));
+               rtx 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, k * UNITS_PER_WORD);
@@ -396,8 +359,7 @@ save_call_clobbered_regs (insn_mode)
     {
       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 i, j;
       int regno;
 
       /* Compute hard regs live at start of block -- this is the
@@ -406,31 +368,20 @@ save_call_clobbered_regs (insn_mode)
         saved because we restore all of them before the end of the basic
         block.  */
 
-#ifdef HARD_REG_SET
-      hard_regs_live = *regs_live;
-#else
-      COPY_HARD_REG_SET (hard_regs_live, regs_live);
-#endif
-
+      REG_SET_TO_HARD_REG_SET (hard_regs_live, regs_live);
       CLEAR_HARD_REG_SET (hard_regs_saved);
       CLEAR_HARD_REG_SET (hard_regs_need_restore);
       n_regs_saved = 0;
 
-      for (offset = 0, i = 0; offset < regset_size; offset++)
-       {
-         if (regs_live[offset] == 0)
-           i += REGSET_ELT_BITS;
-         else
-           for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
-             if ((regs_live[offset] & bit)
-                 && (regno = reg_renumber[i]) >= 0)
-               for (j = regno;
-                    j < regno + HARD_REGNO_NREGS (regno,
-                                                  PSEUDO_REGNO_MODE (i));
-                    j++)
-                 SET_HARD_REG_BIT (hard_regs_live, j);
-
-       }
+      EXECUTE_IF_SET_IN_REG_SET (regs_live, 0, i,
+                                {
+                                  if ((regno = reg_renumber[i]) >= 0)
+                                    for (j = regno;
+                                         j < regno + HARD_REGNO_NREGS (regno,
+                                                                       PSEUDO_REGNO_MODE (i));
+                                         j++)
+                                      SET_HARD_REG_BIT (hard_regs_live, j);
+                                });
 
       /* Now scan the insns in the block, keeping track of what hard
         regs are live as we go.  When we see a call, save the live
@@ -465,32 +416,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)
@@ -525,7 +506,8 @@ save_call_clobbered_regs (insn_mode)
 
 static void
 set_reg_live (reg, setter)
-     rtx reg, setter;
+     rtx reg;
+     rtx setter ATTRIBUTE_UNUSED;
 {
   register int regno, endregno, i;
   enum machine_mode mode = GET_MODE (reg);
@@ -660,9 +642,9 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
      enum machine_mode insn_mode;
      int maxrestore;
 {
-  rtx pat;
-  enum insn_code code;
-  int i, numregs;
+  rtx pat = NULL_RTX;
+  enum insn_code code = CODE_FOR_nothing;
+  int numregs = 0;
 
   /* A common failure mode if register status is not correct in the RTL
      is for this routine to be called with a REGNO we didn't expect to
@@ -674,14 +656,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
@@ -720,8 +694,9 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
          if (! ok)
            continue;
 
-          pat = gen_rtx (SET, VOIDmode, regno_save_mem[regno][i],
-                    gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]), regno));
+          pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i],
+                            gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
+                                         regno));
           code = reg_save_code[regno][i];
 
          /* Set hard_regs_saved for all the registers we saved.  */
@@ -759,9 +734,9 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
          if (! ok)
            continue;
            
-          pat = gen_rtx (SET, VOIDmode,
-                        gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]), 
-                                 regno), 
+          pat = gen_rtx_SET (VOIDmode,
+                            gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]), 
+                                         regno), 
                         regno_save_mem[regno][i]);
           code = reg_restore_code[regno][i];