OSDN Git Service

PR target/39942
[pf3gnuchains/gcc-fork.git] / gcc / ira-lives.c
index f4b2d6d..4390c6f 100644 (file)
@@ -1,5 +1,5 @@
 /* IRA processing allocno lives to build allocno live ranges.
-   Copyright (C) 2006, 2007, 2008
+   Copyright (C) 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "target.h"
 #include "flags.h"
+#include "except.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "insn-config.h"
@@ -75,6 +76,11 @@ static HARD_REG_SET hard_regs_live;
 /* The loop tree node corresponding to the current basic block.  */
 static ira_loop_tree_node_t curr_bb_node;
 
+/* The number of the last processed call.  */
+static int last_call_num;
+/* The number of last call at which given allocno was saved.  */
+static int *allocno_saved_at_call;
+
 /* The function processing birth of register REGNO.  It updates living
    hard regs and conflict hard regs for living allocnos or starts a
    new live range for the allocno corresponding to REGNO if it is
@@ -112,18 +118,23 @@ make_regno_born (int regno)
 static void
 update_allocno_pressure_excess_length (ira_allocno_t a)
 {
-  int start;
-  enum reg_class cover_class;
+  int start, i;
+  enum reg_class cover_class, cl;
   allocno_live_range_t p;
 
   cover_class = ALLOCNO_COVER_CLASS (a);
-  if (high_pressure_start_point[cover_class] < 0)
-    return;
-  p = ALLOCNO_LIVE_RANGES (a);
-  ira_assert (p != NULL);
-  start = (high_pressure_start_point[cover_class] > p->start
-          ? high_pressure_start_point[cover_class] : p->start);
-  ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) += curr_point - start + 1;
+  for (i = 0;
+       (cl = ira_reg_class_super_classes[cover_class][i]) != LIM_REG_CLASSES;
+       i++)
+    {
+      if (high_pressure_start_point[cl] < 0)
+       continue;
+      p = ALLOCNO_LIVE_RANGES (a);
+      ira_assert (p != NULL);
+      start = (high_pressure_start_point[cl] > p->start
+              ? high_pressure_start_point[cl] : p->start);
+      ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) += curr_point - start + 1;
+    }
 }
 
 /* Process the death of register REGNO.  This updates hard_regs_live
@@ -160,24 +171,28 @@ static int curr_reg_pressure[N_REG_CLASSES];
 static void
 set_allocno_live (ira_allocno_t a)
 {
-  int nregs;
-  enum reg_class cover_class;
+  int i;
+  enum reg_class cover_class, cl;
 
+  /* Invalidate because it is referenced.  */
+  allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
   if (sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
     return;
   sparseset_set_bit (allocnos_live, ALLOCNO_NUM (a));
   IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), hard_regs_live);
   IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), hard_regs_live);
   cover_class = ALLOCNO_COVER_CLASS (a);
-  nregs = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)];
-  curr_reg_pressure[cover_class] += nregs;
-  if (high_pressure_start_point[cover_class] < 0
-      && (curr_reg_pressure[cover_class]
-         > ira_available_class_regs[cover_class]))
-    high_pressure_start_point[cover_class] = curr_point;
-  if (curr_bb_node->reg_pressure[cover_class]
-      < curr_reg_pressure[cover_class])
-    curr_bb_node->reg_pressure[cover_class] = curr_reg_pressure[cover_class];
+  for (i = 0;
+       (cl = ira_reg_class_super_classes[cover_class][i]) != LIM_REG_CLASSES;
+       i++)
+    {
+      curr_reg_pressure[cl] += ira_reg_class_nregs[cl][ALLOCNO_MODE (a)];
+      if (high_pressure_start_point[cl] < 0
+         && (curr_reg_pressure[cl] > ira_available_class_regs[cl]))
+       high_pressure_start_point[cl] = curr_point;
+      if (curr_bb_node->reg_pressure[cl] < curr_reg_pressure[cl])
+       curr_bb_node->reg_pressure[cl] = curr_reg_pressure[cl];
+    }
 }
 
 /* Mark allocno A as currently not living and update current register
@@ -186,24 +201,40 @@ set_allocno_live (ira_allocno_t a)
 static void
 clear_allocno_live (ira_allocno_t a)
 {
-  unsigned int i;
-  enum reg_class cover_class;
+  int i;
+  unsigned int j;
+  enum reg_class cover_class, cl;
+  bool set_p;
 
+  /* Invalidate because it is referenced.  */
+  allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
   if (sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
     {
       cover_class = ALLOCNO_COVER_CLASS (a);
-      curr_reg_pressure[cover_class]
-       -= ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)];
-      ira_assert (curr_reg_pressure[cover_class] >= 0);
-      if (high_pressure_start_point[cover_class] >= 0
-         && (curr_reg_pressure[cover_class]
-             <= ira_available_class_regs[cover_class]))
+      set_p = false;
+      for (i = 0;
+          (cl = ira_reg_class_super_classes[cover_class][i])
+            != LIM_REG_CLASSES;
+          i++)
        {
-         EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
-           {
-             update_allocno_pressure_excess_length (ira_allocnos[i]);
-           }
-         high_pressure_start_point[cover_class] = -1;
+         curr_reg_pressure[cl] -= ira_reg_class_nregs[cl][ALLOCNO_MODE (a)];
+         ira_assert (curr_reg_pressure[cl] >= 0);
+         if (high_pressure_start_point[cl] >= 0
+             && curr_reg_pressure[cl] <= ira_available_class_regs[cl])
+           set_p = true;
+       }
+      if (set_p)
+       {
+         EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, j)
+           update_allocno_pressure_excess_length (ira_allocnos[j]);
+         for (i = 0;
+              (cl = ira_reg_class_super_classes[cover_class][i])
+                != LIM_REG_CLASSES;
+              i++)
+           if (high_pressure_start_point[cl] >= 0
+               && curr_reg_pressure[cl] <= ira_available_class_regs[cl])
+             high_pressure_start_point[cl] = -1;
+         
        }
     }
   sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (a));
@@ -216,7 +247,7 @@ clear_allocno_live (ira_allocno_t a)
 static void
 mark_reg_live (rtx reg)
 {
-  int regno;
+  int i, regno;
 
   gcc_assert (REG_P (reg));
   regno = REGNO (reg);
@@ -228,7 +259,11 @@ mark_reg_live (rtx reg)
       if (a != NULL)
        {
          if (sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
-           return;
+           {
+             /* Invalidate because it is referenced.  */
+             allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+             return;
+           }
          set_allocno_live (a);
        }
       make_regno_born (regno);
@@ -236,28 +271,34 @@ mark_reg_live (rtx reg)
   else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
     {
       int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
-      enum reg_class cover_class;
+      enum reg_class cover_class, cl;
 
       while (regno < last)
        {
          if (! TEST_HARD_REG_BIT (hard_regs_live, regno)
              && ! TEST_HARD_REG_BIT (eliminable_regset, regno))
            {
-             cover_class = ira_class_translate[REGNO_REG_CLASS (regno)];
-             if (cover_class != NO_REGS)
+             cover_class = ira_hard_regno_cover_class[regno];
+             for (i = 0;
+                  (cl = ira_reg_class_super_classes[cover_class][i])
+                    != LIM_REG_CLASSES;
+                  i++)
                {
-                 curr_reg_pressure[cover_class]++;
-                 if (high_pressure_start_point[cover_class] < 0
-                     && (curr_reg_pressure[cover_class]
-                         > ira_available_class_regs[cover_class]))
-                   high_pressure_start_point[cover_class] = curr_point;
+                 curr_reg_pressure[cl]++;
+                 if (high_pressure_start_point[cl] < 0
+                     && (curr_reg_pressure[cl]
+                         > ira_available_class_regs[cl]))
+                   high_pressure_start_point[cl] = curr_point;
                }
              make_regno_born (regno);
-             if (cover_class != NO_REGS
-                 && (curr_bb_node->reg_pressure[cover_class]
-                     < curr_reg_pressure[cover_class]))
-               curr_bb_node->reg_pressure[cover_class]
-                 = curr_reg_pressure[cover_class];
+             for (i = 0;
+                  (cl = ira_reg_class_super_classes[cover_class][i])
+                    != LIM_REG_CLASSES;
+                  i++)
+               {
+                 if (curr_bb_node->reg_pressure[cl] < curr_reg_pressure[cl])
+                   curr_bb_node->reg_pressure[cl] = curr_reg_pressure[cl];
+               }
            }
          regno++;
        }
@@ -293,37 +334,52 @@ mark_reg_dead (rtx reg)
       if (a != NULL)
        {
          if (! sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
-           return;
+           {
+             /* Invalidate because it is referenced.  */
+             allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+             return;
+           }
          clear_allocno_live (a);
        }
       make_regno_dead (regno);
     }
   else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
     {
-      unsigned int i;
+      int i;
+      unsigned int j;
       int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
-      enum reg_class cover_class;
+      enum reg_class cover_class, cl;
+      bool set_p;
 
       while (regno < last)
        {
          if (TEST_HARD_REG_BIT (hard_regs_live, regno))
            {
-             cover_class = ira_class_translate[REGNO_REG_CLASS (regno)];
-             if (cover_class != NO_REGS)
+             set_p = false;
+             cover_class = ira_hard_regno_cover_class[regno];
+             for (i = 0;
+                  (cl = ira_reg_class_super_classes[cover_class][i])
+                    != LIM_REG_CLASSES;
+                  i++)
+               {
+                 curr_reg_pressure[cl]--;
+                 if (high_pressure_start_point[cl] >= 0
+                     && curr_reg_pressure[cl] <= ira_available_class_regs[cl])
+                   set_p = true;
+                 ira_assert (curr_reg_pressure[cl] >= 0);
+               }
+             if (set_p)
                {
-                 curr_reg_pressure[cover_class]--;
-                 if (high_pressure_start_point[cover_class] >= 0
-                     && (curr_reg_pressure[cover_class]
-                         <= ira_available_class_regs[cover_class]))
-                   {
-                     EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
-                       {
-                         update_allocno_pressure_excess_length
-                           (ira_allocnos[i]);
-                       }
-                     high_pressure_start_point[cover_class] = -1;
-                   }
-                 ira_assert (curr_reg_pressure[cover_class] >= 0);
+                 EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, j)
+                   update_allocno_pressure_excess_length (ira_allocnos[j]);
+                 for (i = 0;
+                      (cl = ira_reg_class_super_classes[cover_class][i])
+                        != LIM_REG_CLASSES;
+                      i++)
+                   if (high_pressure_start_point[cl] >= 0
+                       && (curr_reg_pressure[cl]
+                           <= ira_available_class_regs[cl]))
+                     high_pressure_start_point[cl] = -1;
                }
              make_regno_dead (regno);
            }
@@ -726,10 +782,11 @@ process_single_reg_class_operands (bool in_p, int freq)
                  [ira_class_hard_regs[cl][0]]) >= 0
              && reg_class_size[cl] <= (unsigned) CLASS_MAX_NREGS (cl, mode))
            {
-             /* ??? FREQ */
-             cost = freq * (in_p
-                            ? ira_register_move_cost[mode][cover_class][cl]
-                            : ira_register_move_cost[mode][cl][cover_class]);
+             cost
+               = (freq
+                  * (in_p
+                     ? ira_get_register_move_cost (mode, cover_class, cl)
+                     : ira_get_register_move_cost (mode, cl, cover_class)));
              ira_allocate_and_set_costs
                (&ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a), cover_class, 0);
              ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a)
@@ -768,8 +825,6 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
   unsigned int j;
   basic_block bb;
   rtx insn;
-  edge e;
-  edge_iterator ei;
   bitmap_iterator bi;
   bitmap reg_live_out;
   unsigned int px;
@@ -792,19 +847,20 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (hard_regs_live, i))
          {
-           enum reg_class cover_class;
+           enum reg_class cover_class, cl;
            
-           cover_class = REGNO_REG_CLASS (i);
-           if (cover_class == NO_REGS)
-             continue;
-           cover_class = ira_class_translate[cover_class];
-           curr_reg_pressure[cover_class]++;
-           if (curr_bb_node->reg_pressure[cover_class]
-               < curr_reg_pressure[cover_class])
-             curr_bb_node->reg_pressure[cover_class]
-               = curr_reg_pressure[cover_class];
-           ira_assert (curr_reg_pressure[cover_class]
-                       <= ira_available_class_regs[cover_class]);
+           cover_class = ira_class_translate[REGNO_REG_CLASS (i)];
+           for (j = 0;
+                (cl = ira_reg_class_super_classes[cover_class][j])
+                  != LIM_REG_CLASSES;
+                j++)
+             {
+               curr_reg_pressure[cl]++;
+               if (curr_bb_node->reg_pressure[cl] < curr_reg_pressure[cl])
+                 curr_bb_node->reg_pressure[cl] = curr_reg_pressure[cl];
+               ira_assert (curr_reg_pressure[cl]
+                           <= ira_available_class_regs[cl]);
+             }
          }
       EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
        {
@@ -821,6 +877,9 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
       if (freq == 0)
        freq = 1;
 
+      /* Invalidate all allocno_saved_at_call entries.  */
+      last_call_num++;
+
       /* Scan the code of this basic block, noting which allocnos and
         hard regs are born or die.
 
@@ -902,12 +961,21 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
 
          if (call_p)
            {
+             last_call_num++;
              /* The current set of live allocnos are live across the call.  */
              EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
                {
                  ira_allocno_t a = ira_allocnos[i];
                  
-                 ALLOCNO_CALL_FREQ (a) += freq;
+                 if (allocno_saved_at_call[i] != last_call_num)
+                   /* Here we are mimicking caller-save.c behaviour
+                      which does not save hard register at a call if
+                      it was saved on previous call in the same basic
+                      block and the hard register was not mentioned
+                      between the two calls.  */
+                   ALLOCNO_CALL_FREQ (a) += freq;
+                 /* Mark it as saved at the next call.  */
+                 allocno_saved_at_call[i] = last_call_num + 1;
                  ALLOCNO_CALLS_CROSSED_NUM (a)++;
                  /* Don't allocate allocnos that cross setjmps or any
                     call, if this function receives a nonlocal
@@ -919,6 +987,13 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
                      SET_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a));
                      SET_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
                    }
+                 if (can_throw_internal (insn))
+                   {
+                     IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a),
+                                       call_used_reg_set);
+                     IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
+                                       call_used_reg_set);
+                   }
                }
            }
          
@@ -957,16 +1032,23 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
          curr_point++;
        }
 
+#ifdef EH_RETURN_DATA_REGNO
+      if (bb_has_eh_pred (bb))
+       for (j = 0; ; ++j)
+         {
+           unsigned int regno = EH_RETURN_DATA_REGNO (j);
+           if (regno == INVALID_REGNUM)
+             break;
+           make_regno_born (regno);
+         }
+#endif
+
       /* Allocnos 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 caller-save, fixup_abnormal_edges and
         possibly the table driven EH machinery are not quite ready to
         handle such allocnos live across such edges.  */
-      FOR_EACH_EDGE (e, ei, bb->preds)
-       if (e->flags & EDGE_ABNORMAL)
-         break;
-
-      if (e != NULL)
+      if (bb_has_abnormal_pred (bb))
        {
 #ifdef STACK_REGS
          EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, px)
@@ -1153,6 +1235,10 @@ ira_create_allocno_live_ranges (void)
 {
   allocnos_live = sparseset_alloc (ira_allocnos_num);
   curr_point = 0;
+  last_call_num = 0;
+  allocno_saved_at_call
+    = (int *) ira_allocate (ira_allocnos_num * sizeof (int));
+  memset (allocno_saved_at_call, 0, ira_allocnos_num * sizeof (int));
   ira_traverse_loop_tree (true, ira_loop_tree_root, NULL,
                          process_bb_node_lives);
   ira_max_point = curr_point;
@@ -1160,6 +1246,7 @@ ira_create_allocno_live_ranges (void)
   if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
     print_live_ranges (ira_dump_file);
   /* Clean up.  */
+  ira_free (allocno_saved_at_call);
   sparseset_free (allocnos_live);
 }