2008-11-14 Vladimir Makarov <vmakarov@redhat.com>
authorvmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 14 Nov 2008 16:41:56 +0000 (16:41 +0000)
committervmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 14 Nov 2008 16:41:56 +0000 (16:41 +0000)
PR rtl-optimization/37397
* ira-int.h (struct ira_allocno): New member bad_spill_p.
(ALLOCNO_BAD_SPILL_P): New macro.

* ira-color.c (push_allocnos_to_stack): Check ALLOCNO_BAD_SPILL_P.

* ira-build.c (ira_create_allocno): Initialize
ALLOCNO_BAD_SPILL_P.
(create_cap_allocno, propagate_allocno_info,
remove_unnecessary_allocnos): Set up or update
ALLOCNO_BAD_SPILL_P.
(update_bad_spill_attribute): New function.
(ira_build): Call it.

* ira-costs.c (record_reg_classes): Set up ALLOCNO_BAD_SPILL_P.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@141860 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/ira-build.c
gcc/ira-color.c
gcc/ira-costs.c
gcc/ira-int.h

index c54e678..67c796e 100644 (file)
@@ -1,3 +1,21 @@
+2008-11-14  Vladimir Makarov  <vmakarov@redhat.com>
+
+       PR rtl-optimization/37397
+       * ira-int.h (struct ira_allocno): New member bad_spill_p.
+       (ALLOCNO_BAD_SPILL_P): New macro.
+
+       * ira-color.c (push_allocnos_to_stack): Check ALLOCNO_BAD_SPILL_P.
+
+       * ira-build.c (ira_create_allocno): Initialize
+       ALLOCNO_BAD_SPILL_P.
+       (create_cap_allocno, propagate_allocno_info,
+       remove_unnecessary_allocnos): Set up or update
+       ALLOCNO_BAD_SPILL_P.
+       (update_bad_spill_attribute): New function.
+       (ira_build): Call it.
+
+       * ira-costs.c (record_reg_classes): Set up ALLOCNO_BAD_SPILL_P.
+       
 2008-11-14  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/38104
index 295825c..110da63 100644 (file)
@@ -456,6 +456,7 @@ ira_create_allocno (int regno, bool cap_p, ira_loop_tree_node_t loop_tree_node)
   ALLOCNO_SOMEWHERE_RENAMED_P (a) = false;
   ALLOCNO_CHILD_RENAMED_P (a) = false;
   ALLOCNO_DONT_REASSIGN_P (a) = false;
+  ALLOCNO_BAD_SPILL_P (a) = false;
   ALLOCNO_IN_GRAPH_P (a) = false;
   ALLOCNO_ASSIGNED_P (a) = false;
   ALLOCNO_MAY_BE_SPILLED_P (a) = false;
@@ -775,6 +776,7 @@ create_cap_allocno (ira_allocno_t a)
   ira_allocate_and_copy_costs
     (&ALLOCNO_CONFLICT_HARD_REG_COSTS (cap), cover_class,
      ALLOCNO_CONFLICT_HARD_REG_COSTS (a));
+  ALLOCNO_BAD_SPILL_P (cap) = ALLOCNO_BAD_SPILL_P (a);
   ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a);
   ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a);
   ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a);
@@ -1490,6 +1492,8 @@ propagate_allocno_info (void)
          && bitmap_bit_p (ALLOCNO_LOOP_TREE_NODE (a)->border_allocnos,
                           ALLOCNO_NUM (a)))
        {
+         if (! ALLOCNO_BAD_SPILL_P (a))
+           ALLOCNO_BAD_SPILL_P (parent_a) = false;
          ALLOCNO_NREFS (parent_a) += ALLOCNO_NREFS (a);
          ALLOCNO_FREQ (parent_a) += ALLOCNO_FREQ (a);
          ALLOCNO_CALL_FREQ (parent_a) += ALLOCNO_CALL_FREQ (a);
@@ -1777,6 +1781,8 @@ remove_unnecessary_allocnos (void)
                  += ALLOCNO_CALLS_CROSSED_NUM (a);
                ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a)
                  += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a);
+               if (! ALLOCNO_BAD_SPILL_P (a))
+                 ALLOCNO_BAD_SPILL_P (parent_a) = false;
 #ifdef STACK_REGS
                if (ALLOCNO_TOTAL_NO_STACK_REG_P (a))
                  ALLOCNO_TOTAL_NO_STACK_REG_P (parent_a) = true;
@@ -1825,6 +1831,69 @@ remove_unnecessary_regions (void)
 
 \f
 
+/* At this point true value of allocno attribute bad_spill_p means
+   that there is an insn where allocno occurs and where the allocno
+   can not be used as memory.  The function updates the attribute, now
+   it can be true only for allocnos which can not be used as memory in
+   an insn and in whose live ranges there is other allocno deaths.
+   Spilling allocnos with true value will not improve the code because
+   it will not make other allocnos colorable and additional reloads
+   for the corresponding pseudo will be generated in reload pass for
+   each insn it occurs.
+
+   This is a trick mentioned in one classic article of Chaitin etc
+   which is frequently omitted in other implementations of RA based on
+   graph coloring.  */
+static void
+update_bad_spill_attribute (void)
+{
+  int i;
+  ira_allocno_t a;
+  ira_allocno_iterator ai;
+  allocno_live_range_t r;
+  enum reg_class cover_class;
+  bitmap_head dead_points[N_REG_CLASSES];
+
+  for (i = 0; i < ira_reg_class_cover_size; i++)
+    {
+      cover_class = ira_reg_class_cover[i];
+      bitmap_initialize (&dead_points[cover_class], &reg_obstack);
+    }
+  FOR_EACH_ALLOCNO (a, ai)
+    {
+      cover_class = ALLOCNO_COVER_CLASS (a);
+      if (cover_class == NO_REGS)
+       continue;
+      for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
+       bitmap_set_bit (&dead_points[cover_class], r->finish);
+    }
+  FOR_EACH_ALLOCNO (a, ai)
+    {
+      cover_class = ALLOCNO_COVER_CLASS (a);
+      if (cover_class == NO_REGS)
+       continue;
+      if (! ALLOCNO_BAD_SPILL_P (a))
+       continue;
+      for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
+       {
+         for (i = r->start + 1; i < r->finish; i++)
+           if (bitmap_bit_p (&dead_points[cover_class], i))
+             break;
+         if (i < r->finish)
+           break;
+       }
+      if (r != NULL)
+       ALLOCNO_BAD_SPILL_P (a) = false;
+    }
+  for (i = 0; i < ira_reg_class_cover_size; i++)
+    {
+      cover_class = ira_reg_class_cover[i];
+      bitmap_clear (&dead_points[cover_class]);
+    }
+}
+
+\f
+
 /* Set up minimal and maximal live range points for allocnos.  */
 static void
 setup_min_max_allocno_live_range_point (void)
@@ -2438,6 +2507,7 @@ ira_build (bool loops_p)
   ira_create_allocno_live_ranges ();
   remove_unnecessary_regions ();
   ira_compress_allocno_live_ranges ();
+  update_bad_spill_attribute ();
   loops_p = more_one_region_p ();
   if (loops_p)
     {
index 59589c9..eea3b2c 100644 (file)
@@ -1187,7 +1187,10 @@ push_allocnos_to_stack (void)
                          * ira_reg_class_nregs[ALLOCNO_COVER_CLASS
                                                (i_allocno)]
                          [ALLOCNO_MODE (i_allocno)] + 1));
-                 if (allocno == NULL || allocno_pri > i_allocno_pri
+                 if (allocno == NULL
+                     || (! ALLOCNO_BAD_SPILL_P (i_allocno)
+                         && ALLOCNO_BAD_SPILL_P (allocno))
+                     || allocno_pri > i_allocno_pri
                      || (allocno_pri == i_allocno_pri
                          && (allocno_cost > i_allocno_cost
                              || (allocno_cost == i_allocno_cost 
index 14d473e..280cbb5 100644 (file)
@@ -187,6 +187,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
   int alt;
   int i, j, k;
   rtx set;
+  int insn_allows_mem[MAX_RECOG_OPERANDS];
+
+  for (i = 0; i < n_ops; i++)
+    insn_allows_mem[i] = 0;
 
   /* Process each alternative, each time minimizing an operand's cost
      with the cost for each operand in that alternative.  */
@@ -236,6 +240,8 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
              j = p[0] - '0';
              classes[i] = classes[j];
              allows_mem[i] = allows_mem[j];
+             if (allows_mem[i])
+               insn_allows_mem[i] = 1;
 
              if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
                {
@@ -302,6 +308,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                       + (recog_data.operand_type[i] != OP_OUT
                          ? ira_memory_move_cost[mode][classes[i]][1] : 0)
                       - allows_mem[i]) * frequency;
+
                  /* If we have assigned a class to this allocno in our
                     first pass, add a cost to this alternative
                     corresponding to what we would add if this allocno
@@ -380,7 +387,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                  /* It doesn't seem worth distinguishing between
                     offsettable and non-offsettable addresses
                     here.  */
-                 allows_mem[i] = 1;
+                 insn_allows_mem[i] = allows_mem[i] = 1;
                  if (MEM_P (op))
                    win = 1;
                  break;
@@ -456,7 +463,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                      || (CONSTANT_P (op)
                          && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))))
                    win = 1;
-                 allows_mem[i] = 1;
+                 insn_allows_mem[i] = allows_mem[i] = 1;
                case 'r':
                  classes[i] = ira_reg_class_union[classes[i]][GENERAL_REGS];
                  break;
@@ -472,7 +479,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                  if (EXTRA_MEMORY_CONSTRAINT (c, p))
                    {
                      /* Every MEM can be reloaded to fit.  */
-                     allows_mem[i] = 1;
+                     insn_allows_mem[i] = allows_mem[i] = 1;
                      if (MEM_P (op))
                        win = 1;
                    }
@@ -625,6 +632,18 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
          }
     }
 
+  for (i = 0; i < n_ops; i++)
+    {
+      ira_allocno_t a;
+      rtx op = ops[i];
+
+      if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
+       continue;
+      a = ira_curr_regno_allocno_map [REGNO (op)];
+      if (! ALLOCNO_BAD_SPILL_P (a) && insn_allows_mem[i] == 0)
+       ALLOCNO_BAD_SPILL_P (a) = true;
+    }
+
   /* If this insn is a single set copying operand 1 to operand 0 and
      one operand is an allocno with the other a hard reg or an allocno
      that prefers a hard register that is in its own register class
@@ -867,6 +886,7 @@ record_address_regs (enum machine_mode mode, rtx x, int context,
        if (REGNO (x) < FIRST_PSEUDO_REGISTER)
          break;
 
+       ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[REGNO (x)]) = true;
        pp = COSTS_OF_ALLOCNO (allocno_costs,
                               ALLOCNO_NUM (ira_curr_regno_allocno_map
                                            [REGNO (x)]));
index c5e4bec..0ed1ec3 100644 (file)
@@ -351,6 +351,10 @@ struct ira_allocno
      region and all its subregions recursively.  */
   unsigned int no_stack_reg_p : 1, total_no_stack_reg_p : 1;
 #endif
+  /* TRUE value means that there is no sense to spill the allocno
+     during coloring because the spill will result in additional
+     reloads in reload pass.  */
+  unsigned int bad_spill_p : 1;
   /* TRUE value means that the allocno was not removed yet from the
      conflicting graph during colouring.  */
   unsigned int in_graph_p : 1;
@@ -435,6 +439,7 @@ struct ira_allocno
 #define ALLOCNO_NO_STACK_REG_P(A) ((A)->no_stack_reg_p)
 #define ALLOCNO_TOTAL_NO_STACK_REG_P(A) ((A)->total_no_stack_reg_p)
 #endif
+#define ALLOCNO_BAD_SPILL_P(A) ((A)->bad_spill_p)
 #define ALLOCNO_IN_GRAPH_P(A) ((A)->in_graph_p)
 #define ALLOCNO_ASSIGNED_P(A) ((A)->assigned_p)
 #define ALLOCNO_MAY_BE_SPILLED_P(A) ((A)->may_be_spilled_p)