OSDN Git Service

* config/linux.h (ASM_COMMENT_START): Remove from here,
[pf3gnuchains/gcc-fork.git] / gcc / caller-save.c
index cc356c3..c808eca 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"
@@ -28,7 +30,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 +44,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 +59,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 +79,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.
 
@@ -174,11 +144,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
@@ -202,10 +172,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;
@@ -213,7 +183,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)
            {
@@ -292,7 +263,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 
@@ -314,19 +285,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 +317,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;
-
-               if (WORDS_BIG_ENDIAN) 
-                 offset = k * UNITS_PER_WORD;
-               else
-                 offset =  - k * UNITS_PER_WORD;
+               /* 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));
 
-               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;
          }
@@ -380,8 +357,8 @@ save_call_clobbered_regs (insn_mode)
   for (b = 0; b < n_basic_blocks; b++)
     {
       regset regs_live = basic_block_live_at_start[b];
-      REGSET_ELT_TYPE bit;
-      int offset, i, j;
+      rtx prev_block_last = PREV_INSN (basic_block_head[b]);
+      int i, j;
       int regno;
 
       /* Compute hard regs live at start of block -- this is the
@@ -390,31 +367,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
@@ -449,32 +415,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 +492,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 +593,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;
@@ -638,9 +640,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
@@ -652,14 +654,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
@@ -698,8 +692,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.  */
@@ -737,9 +732,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];