OSDN Git Service

2006-01-26 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index 8644817..2186388 100644 (file)
@@ -1,6 +1,6 @@
 /* Allocate registers for pseudo-registers that span basic blocks.
    Copyright (C) 1987, 1988, 1991, 1994, 1996, 1997, 1998,
-   1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 #include "config.h"
@@ -36,6 +36,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "reload.h"
 #include "output.h"
 #include "toplev.h"
+#include "tree-pass.h"
+#include "timevar.h"
 
 /* This pass of the compiler performs global register allocation.
    It assigns hard register numbers to all the pseudo registers
@@ -95,6 +97,9 @@ struct allocno
   /* Number of calls crossed by each allocno.  */
   int calls_crossed;
 
+  /* Number of calls that might throw crossed by each allocno.  */
+  int throwing_calls_crossed;
+
   /* Number of refs to each allocno.  */
   int n_refs;
 
@@ -166,7 +171,7 @@ static int *reg_may_share;
 
 static INT_TYPE *conflicts;
 
-/* Number of ints require to hold max_allocno bits.
+/* Number of ints required to hold max_allocno bits.
    This is the length of a row in `conflicts'.  */
 
 static int allocno_row_words;
@@ -309,7 +314,6 @@ static void reg_dies (int, enum machine_mode, struct insn_chain *);
 static void allocate_bb_info (void);
 static void free_bb_info (void);
 static bool check_earlyclobber (rtx);
-static bool regclass_intersect (enum reg_class, enum reg_class);
 static void mark_reg_use_for_earlyclobber_1 (rtx *, void *);
 static int mark_reg_use_for_earlyclobber (rtx *, void *);
 static void calculate_local_reg_bb_info (void);
@@ -328,7 +332,7 @@ static void make_accurate_live_analysis (void);
    Return value is nonzero if reload failed
    and we must not do any more for this function.  */
 
-int
+static int
 global_alloc (FILE *file)
 {
   int retval;
@@ -485,6 +489,8 @@ global_alloc (FILE *file)
        allocno[num].reg = i;
        allocno[num].size = PSEUDO_REGNO_SIZE (i);
        allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
+       allocno[num].throwing_calls_crossed
+         += REG_N_THROWING_CALLS_CROSSED (i);
        allocno[num].n_refs += REG_N_REFS (i);
        allocno[num].freq += REG_FREQ (i);
        if (allocno[num].live_length < REG_LIVE_LENGTH (i))
@@ -610,12 +616,12 @@ global_alloc (FILE *file)
       free (allocno_order);
     }
 
-  /* Do the reloads now while the allocno data still exist, so that we can
+  /* Do the reloads now while the allocno data still exists, so that we can
      try to assign new hard regs to any pseudo regs that are spilled.  */
 
 #if 0 /* We need to eliminate regs even if there is no rtl code,
         for the sake of debugging information.  */
-  if (n_basic_blocks > 0)
+  if (n_basic_blocks > NUM_FIXED_BLOCKS)
 #endif
     {
       build_insn_chain (get_insns ());
@@ -695,7 +701,7 @@ global_conflicts (void)
         be explicitly marked in basic_block_live_at_start.  */
 
       {
-       regset old = b->global_live_at_start;
+       regset old = b->il.rtl->global_live_at_start;
        int ax = 0;
        reg_set_iterator rsi;
 
@@ -715,7 +721,7 @@ global_conflicts (void)
        /* Record that each allocno now live conflicts with each hard reg
           now live.
 
-          It is not necessary to mark any conflicts between pseudos as
+          It is not necessary to mark any conflicts between pseudos at
           this point, even for pseudos which are live at the start of
           the basic block.
 
@@ -740,9 +746,9 @@ global_conflicts (void)
 
        /* Pseudos can't go in stack regs at the start of a basic block that
           is reached by an abnormal edge. Likewise for call clobbered regs,
-          because because caller-save, fixup_abnormal_edges, and possibly
-          the table driven EH machinery are not quite ready to handle such
-          regs live across such edges.  */
+          because caller-save, fixup_abnormal_edges and possibly the table
+          driven EH machinery are not quite ready to handle such regs live
+          across such edges.  */
        {
          edge e;
          edge_iterator ei;
@@ -1204,9 +1210,11 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
     {
       /* Did not find a register.  If it would be profitable to
         allocate a call-clobbered register and save and restore it
-        around calls, do that.  */
+        around calls, do that.  Don't do this if it crosses any calls
+        that might throw.  */
       if (! accept_call_clobbered
          && allocno[num].calls_crossed != 0
+         && allocno[num].throwing_calls_crossed == 0
          && CALLER_SAVE_PROFITABLE (allocno[num].n_refs,
                                     allocno[num].calls_crossed))
        {
@@ -1506,7 +1514,7 @@ mark_reg_store (rtx reg, rtx setter, void *data ATTRIBUTE_UNUSED)
     }
 }
 \f
-/* Like mark_reg_set except notice just CLOBBERs; ignore SETs.  */
+/* Like mark_reg_store except notice just CLOBBERs; ignore SETs.  */
 
 static void
 mark_reg_clobber (rtx reg, rtx setter, void *data)
@@ -1727,7 +1735,7 @@ mark_elimination (int from, int to)
 
   FOR_EACH_BB (bb)
     {
-      regset r = bb->global_live_at_start;
+      regset r = bb->il.rtl->global_live_at_start;
       if (REGNO_REG_SET_P (r, from))
        {
          CLEAR_REGNO_REG_SET (r, from);
@@ -1817,7 +1825,7 @@ build_insn_chain (rtx first)
 
          CLEAR_REG_SET (live_relevant_regs);
 
-         EXECUTE_IF_SET_IN_BITMAP (b->global_live_at_start, 0, i, bi)
+         EXECUTE_IF_SET_IN_BITMAP (b->il.rtl->global_live_at_start, 0, i, bi)
            {
              if (i < FIRST_PSEUDO_REGISTER
                  ? ! TEST_HARD_REG_BIT (eliminable_regset, i)
@@ -2011,7 +2019,7 @@ struct bb_info
      killed afterward in the basic block.  */
   bitmap killed, avloc;
   /* Registers partially available and living (in other words whose
-     values were calclualted and used) correspondingly at the start
+     values were calculated and used) correspondingly at the start
      and end of the basic block.  */
   bitmap live_pavin, live_pavout;
 };
@@ -2034,21 +2042,21 @@ allocate_bb_info (void)
   bitmap init;
 
   alloc_aux_for_blocks (sizeof (struct bb_info));
-  init = BITMAP_XMALLOC ();
+  init = BITMAP_ALLOC (NULL);
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     bitmap_set_bit (init, i);
   FOR_EACH_BB (bb)
     {
       bb_info = bb->aux;
-      bb_info->earlyclobber = BITMAP_XMALLOC ();
-      bb_info->avloc = BITMAP_XMALLOC ();
-      bb_info->killed = BITMAP_XMALLOC ();
-      bb_info->live_pavin = BITMAP_XMALLOC ();
-      bb_info->live_pavout = BITMAP_XMALLOC ();
+      bb_info->earlyclobber = BITMAP_ALLOC (NULL);
+      bb_info->avloc = BITMAP_ALLOC (NULL);
+      bb_info->killed = BITMAP_ALLOC (NULL);
+      bb_info->live_pavin = BITMAP_ALLOC (NULL);
+      bb_info->live_pavout = BITMAP_ALLOC (NULL);
       bitmap_copy (bb_info->live_pavin, init);
       bitmap_copy (bb_info->live_pavout, init);
     }
-  BITMAP_XFREE (init);
+  BITMAP_FREE (init);
 }
 
 /* The function frees the allocated info of all basic blocks.  */
@@ -2062,11 +2070,11 @@ free_bb_info (void)
   FOR_EACH_BB (bb)
     {
       bb_info = BB_INFO (bb);
-      BITMAP_XFREE (bb_info->live_pavout);
-      BITMAP_XFREE (bb_info->live_pavin);
-      BITMAP_XFREE (bb_info->killed);
-      BITMAP_XFREE (bb_info->avloc);
-      BITMAP_XFREE (bb_info->earlyclobber);
+      BITMAP_FREE (bb_info->live_pavout);
+      BITMAP_FREE (bb_info->live_pavin);
+      BITMAP_FREE (bb_info->killed);
+      BITMAP_FREE (bb_info->avloc);
+      BITMAP_FREE (bb_info->earlyclobber);
     }
   free_aux_for_blocks ();
 }
@@ -2099,7 +2107,10 @@ mark_reg_change (rtx reg, rtx setter, void *data)
 /* Classes of registers which could be early clobbered in the current
    insn.  */
 
-static varray_type earlyclobber_regclass;
+DEF_VEC_I(int);
+DEF_VEC_ALLOC_I(int,heap);
+
+static VEC(int,heap) *earlyclobber_regclass;
 
 /* This function finds and stores register classes that could be early
    clobbered in INSN.  If any earlyclobber classes are found, the function
@@ -2113,7 +2124,7 @@ check_earlyclobber (rtx insn)
 
   extract_insn (insn);
 
-  VARRAY_POP_ALL (earlyclobber_regclass);
+  VEC_truncate (int, earlyclobber_regclass, 0);
   for (opno = 0; opno < recog_data.n_operands; opno++)
     {
       char c;
@@ -2150,13 +2161,23 @@ check_earlyclobber (rtx insn)
            case ',':
              if (amp_p && class != NO_REGS)
                {
+                 int rc;
+
                  found = true;
-                 for (i = VARRAY_ACTIVE_SIZE (earlyclobber_regclass) - 1;
-                      i >= 0; i--)
-                   if (VARRAY_INT (earlyclobber_regclass, i) == (int) class)
-                     break;
-                 if (i < 0)
-                   VARRAY_PUSH_INT (earlyclobber_regclass, (int) class);
+                 for (i = 0;
+                      VEC_iterate (int, earlyclobber_regclass, i, rc);
+                      i++)
+                   {
+                     if (rc == (int) class)
+                       goto found_rc;
+                   }
+
+                 /* We use VEC_quick_push here because
+                    earlyclobber_regclass holds no more than
+                    N_REG_CLASSES elements. */
+                 VEC_quick_push (int, earlyclobber_regclass, (int) class);
+               found_rc:
+                 ;
                }
              
              amp_p = false;
@@ -2180,22 +2201,6 @@ check_earlyclobber (rtx insn)
   return found;
 }
 
-/* The function returns true if register classes C1 and C2 intersect.  */
-
-static bool
-regclass_intersect (enum reg_class c1, enum reg_class c2)
-{
-  HARD_REG_SET rs, zero;
-
-  CLEAR_HARD_REG_SET (zero);
-  COPY_HARD_REG_SET(rs, reg_class_contents [c1]);
-  AND_HARD_REG_SET (rs, reg_class_contents [c2]);
-  GO_IF_HARD_REG_EQUAL (zero, rs, yes);
-  return true;
- yes:
-  return false;
-}
-
 /* The function checks that pseudo-register *X has a class
    intersecting with the class of pseudo-register could be early
    clobbered in the same insn.
@@ -2209,24 +2214,26 @@ mark_reg_use_for_earlyclobber (rtx *x, void *data ATTRIBUTE_UNUSED)
   basic_block bb = data;
   struct bb_info *bb_info = BB_INFO (bb);
 
-  if (GET_CODE (*x) == REG && REGNO (*x) >= FIRST_PSEUDO_REGISTER)
+  if (REG_P (*x) && REGNO (*x) >= FIRST_PSEUDO_REGISTER)
     {
+      int rc;
+
       regno = REGNO (*x);
       if (bitmap_bit_p (bb_info->killed, regno)
          || bitmap_bit_p (bb_info->avloc, regno))
        return 0;
       pref_class = reg_preferred_class (regno);
       alt_class = reg_alternate_class (regno);
-      for (i = VARRAY_ACTIVE_SIZE (earlyclobber_regclass) - 1; i >= 0; i--)
-       if (regclass_intersect (VARRAY_INT (earlyclobber_regclass, i),
-                               pref_class)
-           || (VARRAY_INT (earlyclobber_regclass, i) != NO_REGS
-               && regclass_intersect (VARRAY_INT (earlyclobber_regclass, i),
-                                      alt_class)))
-         {
-           bitmap_set_bit (bb_info->earlyclobber, regno);
-           break;
-         }
+      for (i = 0; VEC_iterate (int, earlyclobber_regclass, i, rc); i++)
+       {
+         if (reg_classes_intersect_p (rc, pref_class)
+             || (rc != NO_REGS
+                 && reg_classes_intersect_p (rc, alt_class)))
+           {
+             bitmap_set_bit (bb_info->earlyclobber, regno);
+             break;
+           }
+       }
     }
   return 0;
 }
@@ -2248,8 +2255,9 @@ calculate_local_reg_bb_info (void)
   basic_block bb;
   rtx insn, bound;
 
-  VARRAY_INT_INIT (earlyclobber_regclass, 20,
-                  "classes of registers early clobbered in an insn");
+  /* We know that earlyclobber_regclass holds no more than
+    N_REG_CLASSES elements.  See check_earlyclobber.  */
+  earlyclobber_regclass = VEC_alloc (int, heap, N_REG_CLASSES);
   FOR_EACH_BB (bb)
     {
       bound = NEXT_INSN (BB_END (bb));
@@ -2261,6 +2269,7 @@ calculate_local_reg_bb_info (void)
              note_uses (&PATTERN (insn), mark_reg_use_for_earlyclobber_1, bb);
          }
     }
+  VEC_free (int, heap, earlyclobber_regclass);
 }
 
 /* The function sets up reverse post-order number of each basic
@@ -2272,9 +2281,9 @@ set_up_bb_rts_numbers (void)
   int i;
   int *rts_order;
   
-  rts_order = xmalloc (sizeof (int) * n_basic_blocks);
-  flow_reverse_top_sort_order_compute (rts_order);
-  for (i = 0; i < n_basic_blocks; i++)
+  rts_order = xmalloc (sizeof (int) * (n_basic_blocks - NUM_FIXED_BLOCKS));
+  post_order_compute (rts_order, false);
+  for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++)
     BB_INFO_BY_INDEX (rts_order [i])->rts_number = i;
   free (rts_order);
 }
@@ -2307,22 +2316,22 @@ calculate_reg_pav (void)
   basic_block bb, succ;
   edge e;
   int i, nel;
-  varray_type bbs, new_bbs, temp;
+  VEC(basic_block,heap) *bbs, *new_bbs, *temp;
   basic_block *bb_array;
   sbitmap wset;
 
-  VARRAY_BB_INIT (bbs, n_basic_blocks, "basic blocks");
-  VARRAY_BB_INIT (new_bbs, n_basic_blocks, "basic blocks for the next iter.");
-  temp_bitmap = BITMAP_XMALLOC ();
+  bbs = VEC_alloc (basic_block, heap, n_basic_blocks);
+  new_bbs = VEC_alloc (basic_block, heap, n_basic_blocks);
+  temp_bitmap = BITMAP_ALLOC (NULL);
   FOR_EACH_BB (bb)
     {
-      VARRAY_PUSH_BB (bbs, bb);
+      VEC_quick_push (basic_block, bbs, bb);
     }
   wset = sbitmap_alloc (n_basic_blocks + 1);
-  while (VARRAY_ACTIVE_SIZE (bbs))
+  while (VEC_length (basic_block, bbs))
     {
-      bb_array = &VARRAY_BB (bbs, 0);
-      nel = VARRAY_ACTIVE_SIZE (bbs);
+      bb_array = VEC_address (basic_block, bbs);
+      nel = VEC_length (basic_block, bbs);
       qsort (bb_array, nel, sizeof (basic_block), rpost_cmp);
       sbitmap_zero (wset);
       for (i = 0; i < nel; i++)
@@ -2342,10 +2351,10 @@ calculate_reg_pav (void)
              if (pred->index != ENTRY_BLOCK)
                bitmap_ior_into (bb_live_pavin, BB_INFO (pred)->live_pavout);
            }
-         bitmap_and_into (bb_live_pavin, bb->global_live_at_start);
+         bitmap_and_into (bb_live_pavin, bb->il.rtl->global_live_at_start);
          bitmap_ior_and_compl (temp_bitmap, bb_info->avloc,
                                bb_live_pavin, bb_info->killed);
-         bitmap_and_into (temp_bitmap, bb->global_live_at_end);
+         bitmap_and_into (temp_bitmap, bb->il.rtl->global_live_at_end);
          if (! bitmap_equal_p (temp_bitmap, bb_live_pavout))
            {
              bitmap_copy (bb_live_pavout, temp_bitmap);
@@ -2356,7 +2365,7 @@ calculate_reg_pav (void)
                      && !TEST_BIT (wset, succ->index))
                    {
                      SET_BIT (wset, succ->index);
-                     VARRAY_PUSH_BB (new_bbs, succ);
+                     VEC_quick_push (basic_block, new_bbs, succ);
                    }
                }
            }
@@ -2364,10 +2373,12 @@ calculate_reg_pav (void)
       temp = bbs;
       bbs = new_bbs;
       new_bbs = temp;
-      VARRAY_POP_ALL (new_bbs);
+      VEC_truncate (basic_block, new_bbs, 0);
     }
   sbitmap_free (wset);
-  BITMAP_XFREE (temp_bitmap);
+  BITMAP_FREE (temp_bitmap);
+  VEC_free (basic_block, heap, new_bbs);
+  VEC_free (basic_block, heap, bbs);
 }
 
 /* The function modifies partial availability information for two
@@ -2389,7 +2400,7 @@ modify_reg_pav (void)
   CLEAR_HARD_REG_SET (stack_hard_regs);
   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
     SET_HARD_REG_BIT(stack_hard_regs, i);
-  stack_regs = BITMAP_XMALLOC ();
+  stack_regs = BITMAP_ALLOC (NULL);
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     {
       COPY_HARD_REG_SET (used, reg_class_contents[reg_preferred_class (i)]);
@@ -2421,7 +2432,7 @@ modify_reg_pav (void)
 #endif
     }
 #ifdef STACK_REGS
-  BITMAP_XFREE (stack_regs);
+  BITMAP_FREE (stack_regs);
 #endif
 }
 
@@ -2464,8 +2475,55 @@ make_accurate_live_analysis (void)
     {
       bb_info = BB_INFO (bb);
       
-      bitmap_and_into (bb->global_live_at_start, bb_info->live_pavin);
-      bitmap_and_into (bb->global_live_at_end, bb_info->live_pavout);
+      bitmap_and_into (bb->il.rtl->global_live_at_start, bb_info->live_pavin);
+      bitmap_and_into (bb->il.rtl->global_live_at_end, bb_info->live_pavout);
     }
   free_bb_info ();
 }
+/* Run old register allocator.  Return TRUE if we must exit
+   rest_of_compilation upon return.  */
+static void
+rest_of_handle_global_alloc (void)
+{
+  bool failure;
+
+  /* If optimizing, allocate remaining pseudo-regs.  Do the reload
+     pass fixing up any insns that are invalid.  */
+
+  if (optimize)
+    failure = global_alloc (dump_file);
+  else
+    {
+      build_insn_chain (get_insns ());
+      failure = reload (get_insns (), 0);
+    }
+
+  if (dump_enabled_p (pass_global_alloc.static_pass_number))
+    {
+      timevar_push (TV_DUMP);
+      dump_global_regs (dump_file);
+      timevar_pop (TV_DUMP);
+    }
+
+  gcc_assert (reload_completed || failure);
+  reload_completed = !failure;
+}
+
+struct tree_opt_pass pass_global_alloc =
+{
+  "greg",                               /* name */
+  NULL,                                 /* gate */
+  rest_of_handle_global_alloc,          /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_GLOBAL_ALLOC,                      /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'g'                                   /* letter */
+};
+