OSDN Git Service

* decl.c (init_decl_processing): Remove duplicate decl of
[pf3gnuchains/gcc-fork.git] / gcc / resource.c
index eceac56..274cb23 100644 (file)
@@ -1,5 +1,5 @@
 /* Definitions for computing resource usage of specific insns.
-   Copyright (C) 1999 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -19,15 +19,18 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
+#include "system.h"
 #include "toplev.h"
 #include "rtl.h"
+#include "tm_p.h"
 #include "hard-reg-set.h"
-#include "system.h"
 #include "basic-block.h"
+#include "function.h"
 #include "regs.h"
 #include "flags.h"
 #include "output.h"
 #include "resource.h"
+#include "insn-attr.h"
 
 /* This structure is used to record liveness information at the targets or
    fallthrough insns of branches.  We will most likely need the information
@@ -71,10 +74,10 @@ static HARD_REG_SET current_live_regs;
 
 static HARD_REG_SET pending_dead_regs;
 \f
-static void update_live_status         PROTO ((rtx, rtx));
-static int find_basic_block            PROTO ((rtx));
-static rtx next_insn_no_annul          PROTO ((rtx));
-static rtx find_dead_or_set_registers  PROTO ((rtx, struct resources*,
+static void update_live_status         PARAMS ((rtx, rtx, void *));
+static int find_basic_block            PARAMS ((rtx));
+static rtx next_insn_no_annul          PARAMS ((rtx));
+static rtx find_dead_or_set_registers  PARAMS ((rtx, struct resources*,
                                                rtx*, int, struct resources,
                                                struct resources));
 \f
@@ -82,9 +85,10 @@ static rtx find_dead_or_set_registers        PROTO ((rtx, struct resources*,
    It deadens any CLOBBERed registers and livens any SET registers.  */
 
 static void
-update_live_status (dest, x)
+update_live_status (dest, x, data)
      rtx dest;
      rtx x;
+     void *data ATTRIBUTE_UNUSED;
 {
   int first_regno, last_regno;
   int i;
@@ -183,7 +187,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
 {
   register enum rtx_code code = GET_CODE (x);
   register int i, j;
-  register char *format_ptr;
+  register const char *format_ptr;
 
   /* Handle leaf items for which we set resource flags.  Also, special-case
      CALL, SET and CLOBBER operators.  */
@@ -221,7 +225,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
        res->unch_memory = 1;
       else
        res->memory = 1;
-      res->volatil = MEM_VOLATILE_P (x);
+      res->volatil |= MEM_VOLATILE_P (x);
 
       /* Mark registers used to access memory.  */
       mark_referenced_resources (XEXP (x, 0), res, 0);
@@ -242,7 +246,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
       break;
 
     case ASM_OPERANDS:
-      res->volatil = MEM_VOLATILE_P (x);
+      res->volatil |= MEM_VOLATILE_P (x);
 
       /* For all ASM_OPERANDS, we must traverse the vector of input operands.
         We can not just fall through here since then we would be confused
@@ -268,7 +272,9 @@ mark_referenced_resources (x, res, include_delayed_effects)
       mark_referenced_resources (SET_SRC (x), res, 0);
 
       x = SET_DEST (x);
-      if (GET_CODE (x) == SIGN_EXTRACT || GET_CODE (x) == ZERO_EXTRACT)
+      if (GET_CODE (x) == SIGN_EXTRACT
+         || GET_CODE (x) == ZERO_EXTRACT
+         || GET_CODE (x) == STRICT_LOW_PART)
        mark_referenced_resources (x, res, 0);
       else if (GET_CODE (x) == SUBREG)
        x = SUBREG_REG (x);
@@ -590,7 +596,7 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
 {
   register enum rtx_code code;
   register int i, j;
-  register char *format_ptr;
+  register const char *format_ptr;
 
  restart:
 
@@ -710,8 +716,8 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
       if (in_dest)
        {
          res->memory = 1;
-         res->unch_memory = RTX_UNCHANGING_P (x);
-         res->volatil = MEM_VOLATILE_P (x);
+         res->unch_memory |= RTX_UNCHANGING_P (x);
+         res->volatil |= MEM_VOLATILE_P (x);
        }
 
       mark_set_resources (XEXP (x, 0), res, 0, 0);
@@ -739,6 +745,28 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
          SET_HARD_REG_BIT (res->regs, REGNO (x) + i);
       return;
 
+    case UNSPEC_VOLATILE:
+    case ASM_INPUT:
+      /* Traditional asm's are always volatile.  */
+      res->volatil = 1;
+      return;
+
+    case TRAP_IF:
+      res->volatil = 1;
+      break;
+
+    case ASM_OPERANDS:
+      res->volatil |= MEM_VOLATILE_P (x);
+
+      /* For all ASM_OPERANDS, we must traverse the vector of input operands.
+        We can not just fall through here since then we would be confused
+        by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate
+        traditional asms unlike their normal usage.  */
+      
+      for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
+       mark_set_resources (ASM_OPERANDS_INPUT (x, i), res, in_dest, 0);
+      return;
+
     default:
       break;
     }
@@ -944,7 +972,7 @@ mark_target_live_regs (insns, target, res)
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                    && ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
 #endif
-#ifdef PIC_OFFSET_TABLE_REGNUM
+#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
                    && ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
 #endif
                    )
@@ -983,7 +1011,7 @@ mark_target_live_regs (insns, target, res)
                      SET_HARD_REG_BIT (pending_dead_regs, i);
                  }
 
-             note_stores (PATTERN (real_insn), update_live_status);
+             note_stores (PATTERN (real_insn), update_live_status, NULL);
 
              /* If any registers were unused after this insn, kill them.
                 These notes will always be accurate.  */
@@ -1039,8 +1067,8 @@ mark_target_live_regs (insns, target, res)
 
   /* If we hit an unconditional branch, we have another way of finding out
      what is live: we can see what is live at the branch target and include
-     anything used but not set before the branch.  The only things that are
-     live are those that are live using the above test and the test below.  */
+     anything used but not set before the branch.  We add the live
+     resources found using the test below to those found until now. */
 
   if (jump_insn)
     {
@@ -1064,7 +1092,7 @@ mark_target_live_regs (insns, target, res)
          mark_set_resources (insn, &set, 0, 1);
        }
 
-      AND_HARD_REG_SET (res->regs, new_resources.regs);
+      IOR_HARD_REG_SET (res->regs, new_resources.regs);
     }
 
   if (tinfo != NULL)
@@ -1144,14 +1172,9 @@ init_resource_info (epilogue_insn)
     mark_set_resources (epilogue_insn, &end_of_function_needs, 0, 1);
 
   /* Allocate and initialize the tables used by mark_target_live_regs.  */
-  target_hash_table
-    = (struct target_info **) xmalloc ((TARGET_HASH_PRIME
-                                      * sizeof (struct target_info *)));
-  bzero ((char *) target_hash_table,
-        TARGET_HASH_PRIME * sizeof (struct target_info *));
-
-  bb_ticks = (int *) xmalloc (n_basic_blocks * sizeof (int));
-  bzero ((char *) bb_ticks, n_basic_blocks * sizeof (int));
+  target_hash_table = (struct target_info **)
+    xcalloc (TARGET_HASH_PRIME, sizeof (struct target_info *));
+  bb_ticks = (int *) xcalloc (n_basic_blocks, sizeof (int));
 }
 \f
 /* Free up the resources allcated to mark_target_live_regs ().  This
@@ -1216,18 +1239,21 @@ mark_end_of_function_resources (trial, include_delayed_effects)
                             include_delayed_effects);
 }
 \f
-/* Try to find an available hard register of mode MODE at
-   CURRENT_INSN, matching the register class in CLASS_STR. Registers
-   that already have bits set in REG_SET will not be considered.
+/* Try to find a hard register of mode MODE, matching the register class in
+   CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
+   remains available until the end of LAST_INSN.  LAST_INSN may be NULL_RTX,
+   in which case the only condition is that the register must be available
+   before CURRENT_INSN.
+   Registers that already have bits set in REG_SET will not be considered.
 
    If an appropriate register is available, it will be returned and the
    corresponding bit(s) in REG_SET will be set; otherwise, NULL_RTX is
    returned.  */
 
 rtx
-find_free_register (current_insn, class_str, mode, reg_set)
-     rtx current_insn;
-     char *class_str;
+find_free_register (current_insn, last_insn, class_str, mode, reg_set)
+     rtx current_insn, last_insn;
+     const char *class_str;
      int mode;
      HARD_REG_SET *reg_set;
 {
@@ -1238,17 +1264,48 @@ find_free_register (current_insn, class_str, mode, reg_set)
     = (clet == 'r' ? GENERAL_REGS :  REG_CLASS_FROM_LETTER (clet));
 
   mark_target_live_regs (get_insns (), current_insn, &used);
+  if (last_insn)
+    while (current_insn != last_insn)
+      {
+       /* Exclude anything set in this insn.  */
+       mark_set_resources (PATTERN (current_insn), &used, 0, 1);
+       current_insn = next_nonnote_insn (current_insn);
+      }
+
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      int success = 1;
+      int regno;
+      int success;
+
+#ifdef REG_ALLOC_ORDER
+      regno = reg_alloc_order [i];
+#else
+      regno = i;
+#endif
 
-      if (! TEST_HARD_REG_BIT (reg_class_contents[class], i))
+      /* Don't allocate fixed registers.  */
+      if (fixed_regs[regno])
        continue;
-      for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
+      /* Make sure the register is of the right class.  */
+      if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
+       continue;
+      /* And can support the mode we need.  */
+      if (! HARD_REGNO_MODE_OK (regno, mode))
+       continue;
+      /* And that we don't create an extra save/restore.  */
+      if (! call_used_regs[regno] && ! regs_ever_live[regno])
+       continue;
+      /* And we don't clobber traceback for noreturn functions.  */
+      if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
+         && (! reload_completed || frame_pointer_needed))
+       continue;
+
+      success = 1;
+      for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
        {
-         if (TEST_HARD_REG_BIT (*reg_set, i + j)
-             || TEST_HARD_REG_BIT (used.regs, i + j))
+         if (TEST_HARD_REG_BIT (*reg_set, regno + j)
+             || TEST_HARD_REG_BIT (used.regs, regno + j))
            {
              success = 0;
              break;
@@ -1256,12 +1313,33 @@ find_free_register (current_insn, class_str, mode, reg_set)
        }
       if (success)
        {
-         for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
+         for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
            {
-             SET_HARD_REG_BIT (*reg_set, i + j);
+             SET_HARD_REG_BIT (*reg_set, regno + j);
            }
-         return gen_rtx_REG (mode, i);
+         return gen_rtx_REG (mode, regno);
        }
     }
   return NULL_RTX;
 }
+
+/* Return true if REG is dead at CURRENT_INSN.  */
+
+int
+reg_dead_p (current_insn, reg)
+     rtx current_insn, reg;
+{
+  struct resources used;
+  int regno, j;
+
+  mark_target_live_regs (get_insns (), current_insn, &used);
+  
+  regno = REGNO (reg);
+  for (j = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1; j >= 0; j--)
+    {
+      if (TEST_HARD_REG_BIT (used.regs, regno + j))
+       return 0;
+    }
+
+  return 1;
+}