OSDN Git Service

PR middle-end/44828
[pf3gnuchains/gcc-fork.git] / gcc / ira-conflicts.c
index 6d84e56..9e9927a 100644 (file)
@@ -1,5 +1,5 @@
 /* IRA conflict builder.
-   Copyright (C) 2006, 2007, 2008, 2009
+   Copyright (C) 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
@@ -54,10 +54,10 @@ static IRA_INT_TYPE **conflicts;
 #define CONFLICT_ALLOCNO_P(A1, A2)                                     \
   (ALLOCNO_MIN (A1) <= ALLOCNO_CONFLICT_ID (A2)                                \
    && ALLOCNO_CONFLICT_ID (A2) <= ALLOCNO_MAX (A1)                     \
-   && TEST_ALLOCNO_SET_BIT (conflicts[ALLOCNO_NUM (A1)],               \
-                           ALLOCNO_CONFLICT_ID (A2),                   \
-                           ALLOCNO_MIN (A1),                           \
-                           ALLOCNO_MAX (A1)))
+   && TEST_MINMAX_SET_BIT (conflicts[ALLOCNO_NUM (A1)],                        \
+                          ALLOCNO_CONFLICT_ID (A2),                    \
+                          ALLOCNO_MIN (A1),                            \
+                          ALLOCNO_MAX (A1)))
 
 \f
 
@@ -71,7 +71,7 @@ build_conflict_bit_table (void)
   unsigned int j;
   enum reg_class cover_class;
   ira_allocno_t allocno, live_a;
-  allocno_live_range_t r;
+  live_range_t r;
   ira_allocno_iterator ai;
   sparseset allocnos_live;
   int allocno_set_words;
@@ -142,17 +142,17 @@ build_conflict_bit_table (void)
                  /* Don't set up conflict for the allocno with itself.  */
                  && num != (int) j)
                {
-                 SET_ALLOCNO_SET_BIT (conflicts[num],
-                                      ALLOCNO_CONFLICT_ID (live_a),
-                                      ALLOCNO_MIN (allocno),
-                                      ALLOCNO_MAX (allocno));
-                 SET_ALLOCNO_SET_BIT (conflicts[j], id,
-                                      ALLOCNO_MIN (live_a),
-                                      ALLOCNO_MAX (live_a));
+                 SET_MINMAX_SET_BIT (conflicts[num],
+                                     ALLOCNO_CONFLICT_ID (live_a),
+                                     ALLOCNO_MIN (allocno),
+                                     ALLOCNO_MAX (allocno));
+                 SET_MINMAX_SET_BIT (conflicts[j], id,
+                                     ALLOCNO_MIN (live_a),
+                                     ALLOCNO_MAX (live_a));
                }
            }
        }
-         
+
       for (r = ira_finish_point_ranges[i]; r != NULL; r = r->finish_next)
        sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (r->allocno));
     }
@@ -235,7 +235,7 @@ get_dup_num (int op_num, bool use_commut_op_p)
          {
          case 'X':
            return -1;
-           
+
          case 'm':
          case 'o':
            /* Accept a register which might be placed in memory.  */
@@ -254,7 +254,7 @@ get_dup_num (int op_num, bool use_commut_op_p)
 
          case 'g':
            return -1;
-           
+
          case 'r':
          case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
          case 'h': case 'j': case 'k': case 'l':
@@ -276,7 +276,7 @@ get_dup_num (int op_num, bool use_commut_op_p)
 #endif
              break;
            }
-           
+
          case '0': case '1': case '2': case '3': case '4':
          case '5': case '6': case '7': case '8': case '9':
            if (original != -1 && original != c)
@@ -302,21 +302,6 @@ get_dup_num (int op_num, bool use_commut_op_p)
   return dup;
 }
 
-/* Return the operand which should be, in any case, the same as
-   operand with number OP_NUM.  If USE_COMMUT_OP_P is TRUE, the
-   function makes temporarily commutative operand exchange before
-   this.  */
-static rtx
-get_dup (int op_num, bool use_commut_op_p)
-{
-  int n = get_dup_num (op_num, use_commut_op_p);
-
-  if (n < 0)
-    return NULL_RTX;
-  else
-    return recog_data.operand[n];
-}
-
 /* Check that X is REG or SUBREG of REG.  */
 #define REG_SUBREG_P(x)                                                        \
    (REG_P (x) || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))))
@@ -361,7 +346,6 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
   enum reg_class rclass, cover_class;
   enum machine_mode mode;
   ira_copy_t cp;
-  ira_loop_tree_node_t parent;
 
   gcc_assert (REG_SUBREG_P (reg1) && REG_SUBREG_P (reg2));
   only_regs_p = REG_P (reg1) && REG_P (reg2);
@@ -389,7 +373,7 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
                                 ira_curr_regno_allocno_map[REGNO (reg2)],
                                 freq, constraint_p, insn,
                                 ira_curr_loop_tree_node);
-      bitmap_set_bit (ira_curr_loop_tree_node->local_copies, cp->num); 
+      bitmap_set_bit (ira_curr_loop_tree_node->local_copies, cp->num);
       return true;
     }
   else
@@ -412,7 +396,7 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
     cost = ira_get_register_move_cost (mode, cover_class, rclass) * freq;
   else
     cost = ira_get_register_move_cost (mode, rclass, cover_class) * freq;
-  for (;;)
+  do
     {
       ira_allocate_and_set_costs
        (&ALLOCNO_HARD_REG_COSTS (a), cover_class,
@@ -423,21 +407,18 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
       ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[index] -= cost;
       if (ALLOCNO_HARD_REG_COSTS (a)[index] < ALLOCNO_COVER_CLASS_COST (a))
        ALLOCNO_COVER_CLASS_COST (a) = ALLOCNO_HARD_REG_COSTS (a)[index];
-      if (ALLOCNO_CAP (a) != NULL)
-       a = ALLOCNO_CAP (a);
-      else if ((parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) == NULL
-              || (a = parent->regno_allocno_map[ALLOCNO_REGNO (a)]) == NULL)
-       break;
+      a = ira_parent_or_cap_allocno (a);
     }
+  while (a != NULL);
   return true;
 }
 
-/* Process all of the output registers of the current insn and
-   the input register REG (its operand number OP_NUM) which dies in the
-   insn as if there were a move insn between them with frequency
-   FREQ.  */
+/* Process all of the output registers of the current insn which are
+   not bound (BOUND_P) and the input register REG (its operand number
+   OP_NUM) which dies in the insn as if there were a move insn between
+   them with frequency FREQ.  */
 static void
-process_reg_shuffles (rtx reg, int op_num, int freq)
+process_reg_shuffles (rtx reg, int op_num, int freq, bool *bound_p)
 {
   int i;
   rtx another_reg;
@@ -446,11 +427,12 @@ process_reg_shuffles (rtx reg, int op_num, int freq)
   for (i = 0; i < recog_data.n_operands; i++)
     {
       another_reg = recog_data.operand[i];
-      
+
       if (!REG_SUBREG_P (another_reg) || op_num == i
-         || recog_data.operand_type[i] != OP_OUT)
+         || recog_data.operand_type[i] != OP_OUT
+         || bound_p[i])
        continue;
-      
+
       process_regs_for_copy (reg, another_reg, false, NULL_RTX, freq);
     }
 }
@@ -463,8 +445,8 @@ add_insn_allocno_copies (rtx insn)
 {
   rtx set, operand, dup;
   const char *str;
-  bool commut_p, bound_p;
-  int i, j, freq;
+  bool commut_p, bound_p[MAX_RECOG_OPERANDS];
+  int i, j, n, freq;
   
   freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
   if (freq == 0)
@@ -476,38 +458,51 @@ add_insn_allocno_copies (rtx insn)
                        REG_P (SET_SRC (set))
                        ? SET_SRC (set)
                        : SUBREG_REG (SET_SRC (set))) != NULL_RTX)
-    process_regs_for_copy (SET_DEST (set), SET_SRC (set), false, insn, freq);
-  else
     {
-      extract_insn (insn);
-      for (i = 0; i < recog_data.n_operands; i++)
-       {
-         operand = recog_data.operand[i];
-         if (REG_SUBREG_P (operand)
-             && find_reg_note (insn, REG_DEAD,
-                               REG_P (operand)
-                               ? operand : SUBREG_REG (operand)) != NULL_RTX)
-           {
-             str = recog_data.constraints[i];
-             while (*str == ' ' || *str == '\t')
-               str++;
-             bound_p = false;
-             for (j = 0, commut_p = false; j < 2; j++, commut_p = true)
-               if ((dup = get_dup (i, commut_p)) != NULL_RTX
-                   && REG_SUBREG_P (dup)
-                   && process_regs_for_copy (operand, dup, true,
-                                             NULL_RTX, freq))
-                 bound_p = true;
-             if (bound_p)
-               continue;
-             /* If an operand dies, prefer its hard register for the
-                output operands by decreasing the hard register cost
-                or creating the corresponding allocno copies.  The
-                cost will not correspond to a real move insn cost, so
-                make the frequency smaller.  */
-             process_reg_shuffles (operand, i, freq < 8 ? 1 : freq / 8);
-           }
-       }
+      process_regs_for_copy (SET_DEST (set), SET_SRC (set), false, insn, freq);
+      return;
+    }
+  /* Fast check of possibility of constraint or shuffle copies.  If
+     there are no dead registers, there will be no such copies.  */
+  if (! find_reg_note (insn, REG_DEAD, NULL_RTX))
+    return;
+  extract_insn (insn);
+  for (i = 0; i < recog_data.n_operands; i++)
+    bound_p[i] = false;
+  for (i = 0; i < recog_data.n_operands; i++)
+    {
+      operand = recog_data.operand[i];
+      if (! REG_SUBREG_P (operand))
+       continue;
+      str = recog_data.constraints[i];
+      while (*str == ' ' || *str == '\t')
+       str++;
+      for (j = 0, commut_p = false; j < 2; j++, commut_p = true)
+       if ((n = get_dup_num (i, commut_p)) >= 0)
+         {
+           bound_p[n] = true;
+           dup = recog_data.operand[n];
+           if (REG_SUBREG_P (dup)
+               && find_reg_note (insn, REG_DEAD,
+                                 REG_P (operand)
+                                 ? operand
+                                 : SUBREG_REG (operand)) != NULL_RTX)
+             process_regs_for_copy (operand, dup, true, NULL_RTX, freq);
+         }
+    }
+  for (i = 0; i < recog_data.n_operands; i++)
+    {
+      operand = recog_data.operand[i];
+      if (REG_SUBREG_P (operand)
+         && find_reg_note (insn, REG_DEAD,
+                           REG_P (operand)
+                           ? operand : SUBREG_REG (operand)) != NULL_RTX)
+       /* If an operand dies, prefer its hard register for the output
+          operands by decreasing the hard register cost or creating
+          the corresponding allocno copies.  The cost will not
+          correspond to a real move insn cost, so make the frequency
+          smaller.  */
+       process_reg_shuffles (operand, i, freq < 8 ? 1 : freq / 8, bound_p);
     }
 }
 
@@ -534,7 +529,6 @@ propagate_copies (void)
   ira_copy_t cp;
   ira_copy_iterator ci;
   ira_allocno_t a1, a2, parent_a1, parent_a2;
-  ira_loop_tree_node_t parent;
 
   FOR_EACH_COPY (cp, ci)
     {
@@ -543,11 +537,8 @@ propagate_copies (void)
       if (ALLOCNO_LOOP_TREE_NODE (a1) == ira_loop_tree_root)
        continue;
       ira_assert ((ALLOCNO_LOOP_TREE_NODE (a2) != ira_loop_tree_root));
-      parent = ALLOCNO_LOOP_TREE_NODE (a1)->parent;
-      if ((parent_a1 = ALLOCNO_CAP (a1)) == NULL)
-       parent_a1 = parent->regno_allocno_map[ALLOCNO_REGNO (a1)];
-      if ((parent_a2 = ALLOCNO_CAP (a2)) == NULL)
-       parent_a2 = parent->regno_allocno_map[ALLOCNO_REGNO (a2)];
+      parent_a1 = ira_parent_or_cap_allocno (a1);
+      parent_a2 = ira_parent_or_cap_allocno (a2);
       ira_assert (parent_a1 != NULL && parent_a2 != NULL);
       if (! CONFLICT_ALLOCNO_P (parent_a1, parent_a2))
        ira_add_allocno_copy (parent_a1, parent_a2, cp->freq,
@@ -566,16 +557,15 @@ build_allocno_conflicts (ira_allocno_t a)
 {
   int i, px, parent_num;
   int conflict_bit_vec_words_num;
-  ira_loop_tree_node_t parent;
   ira_allocno_t parent_a, another_a, another_parent_a;
   ira_allocno_t *vec;
   IRA_INT_TYPE *allocno_conflicts;
-  ira_allocno_set_iterator asi;
+  minmax_set_iterator asi;
 
   allocno_conflicts = conflicts[ALLOCNO_NUM (a)];
   px = 0;
-  FOR_EACH_ALLOCNO_IN_SET (allocno_conflicts,
-                          ALLOCNO_MIN (a), ALLOCNO_MAX (a), i, asi)
+  FOR_EACH_BIT_IN_MINMAX_SET (allocno_conflicts,
+                             ALLOCNO_MIN (a), ALLOCNO_MAX (a), i, asi)
     {
       another_a = ira_conflict_id_allocno_map[i];
       ira_assert (ira_reg_classes_intersect_p
@@ -602,32 +592,27 @@ build_allocno_conflicts (ira_allocno_t a)
       ALLOCNO_CONFLICT_ALLOCNO_ARRAY_SIZE (a)
        = conflict_bit_vec_words_num * sizeof (IRA_INT_TYPE);
     }
-  parent = ALLOCNO_LOOP_TREE_NODE (a)->parent;
-  if ((parent_a = ALLOCNO_CAP (a)) == NULL
-      && (parent == NULL
-         || (parent_a = parent->regno_allocno_map[ALLOCNO_REGNO (a)])
-         == NULL))
+  parent_a = ira_parent_or_cap_allocno (a);
+  if (parent_a == NULL)
     return;
-  ira_assert (parent != NULL);
   ira_assert (ALLOCNO_COVER_CLASS (a) == ALLOCNO_COVER_CLASS (parent_a));
   parent_num = ALLOCNO_NUM (parent_a);
-  FOR_EACH_ALLOCNO_IN_SET (allocno_conflicts,
-                          ALLOCNO_MIN (a), ALLOCNO_MAX (a), i, asi)
+  FOR_EACH_BIT_IN_MINMAX_SET (allocno_conflicts,
+                             ALLOCNO_MIN (a), ALLOCNO_MAX (a), i, asi)
     {
       another_a = ira_conflict_id_allocno_map[i];
       ira_assert (ira_reg_classes_intersect_p
                  [ALLOCNO_COVER_CLASS (a)][ALLOCNO_COVER_CLASS (another_a)]);
-      if ((another_parent_a = ALLOCNO_CAP (another_a)) == NULL
-         && (another_parent_a = (parent->regno_allocno_map
-                                 [ALLOCNO_REGNO (another_a)])) == NULL)
+      another_parent_a = ira_parent_or_cap_allocno (another_a);
+      if (another_parent_a == NULL)
        continue;
       ira_assert (ALLOCNO_NUM (another_parent_a) >= 0);
       ira_assert (ALLOCNO_COVER_CLASS (another_a)
                  == ALLOCNO_COVER_CLASS (another_parent_a));
-      SET_ALLOCNO_SET_BIT (conflicts[parent_num],
-                          ALLOCNO_CONFLICT_ID (another_parent_a),
-                          ALLOCNO_MIN (parent_a),
-                          ALLOCNO_MAX (parent_a));
+      SET_MINMAX_SET_BIT (conflicts[parent_num],
+                         ALLOCNO_CONFLICT_ID (another_parent_a),
+                         ALLOCNO_MIN (parent_a),
+                         ALLOCNO_MAX (parent_a));
     }
 }
 
@@ -685,68 +670,72 @@ print_hard_reg_set (FILE *file, const char *title, HARD_REG_SET set)
   putc ('\n', file);
 }
 
-/* Print information about allocno or only regno (if REG_P) conflicts
-   to FILE.  */
 static void
-print_conflicts (FILE *file, bool reg_p)
+print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
 {
-  ira_allocno_t a;
-  ira_allocno_iterator ai;
   HARD_REG_SET conflicting_hard_regs;
+  ira_allocno_t conflict_a;
+  ira_allocno_conflict_iterator aci;
+  basic_block bb;
 
-  FOR_EACH_ALLOCNO (a, ai)
+  if (reg_p)
+    fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
+  else
     {
-      ira_allocno_t conflict_a;
-      ira_allocno_conflict_iterator aci;
-      basic_block bb;
-
-      if (reg_p)
-       fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
+      fprintf (file, ";; a%d(r%d,", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
+      if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
+        fprintf (file, "b%d", bb->index);
       else
-       {
-         fprintf (file, ";; a%d(r%d,", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
-         if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
-           fprintf (file, "b%d", bb->index);
-         else
-           fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
-         putc (')', file);
-       }
-      fputs (" conflicts:", file);
-      if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) != NULL)
-       FOR_EACH_ALLOCNO_CONFLICT (a, conflict_a, aci)
-         {
-           if (reg_p)
-             fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
+        fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
+      putc (')', file);
+    }
+  fputs (" conflicts:", file);
+  if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) != NULL)
+    FOR_EACH_ALLOCNO_CONFLICT (a, conflict_a, aci)
+      {
+        if (reg_p)
+          fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
+        else
+          {
+           fprintf (file, " a%d(r%d,", ALLOCNO_NUM (conflict_a),
+                    ALLOCNO_REGNO (conflict_a));
+           if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
+             fprintf (file, "b%d)", bb->index);
            else
-             {
-               fprintf (file, " a%d(r%d,", ALLOCNO_NUM (conflict_a),
-                        ALLOCNO_REGNO (conflict_a));
-               if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
-                 fprintf (file, "b%d)", bb->index);
-               else
-                 fprintf (file, "l%d)",
-                          ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
-             }
+             fprintf (file, "l%d)",
+                      ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
          }
-      COPY_HARD_REG_SET (conflicting_hard_regs,
-                        ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
-      AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
-      AND_HARD_REG_SET (conflicting_hard_regs,
-                       reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
-      print_hard_reg_set (file, "\n;;     total conflict hard regs:",
-                         conflicting_hard_regs);
-      COPY_HARD_REG_SET (conflicting_hard_regs,
-                        ALLOCNO_CONFLICT_HARD_REGS (a));
-      AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
-      AND_HARD_REG_SET (conflicting_hard_regs,
-                       reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
-      print_hard_reg_set (file, ";;     conflict hard regs:",
-                         conflicting_hard_regs);
-    }
+      }
+  COPY_HARD_REG_SET (conflicting_hard_regs,
+                    ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+  AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+  AND_HARD_REG_SET (conflicting_hard_regs,
+                   reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
+  print_hard_reg_set (file, "\n;;     total conflict hard regs:",
+                     conflicting_hard_regs);
+  COPY_HARD_REG_SET (conflicting_hard_regs,
+                    ALLOCNO_CONFLICT_HARD_REGS (a));
+  AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+  AND_HARD_REG_SET (conflicting_hard_regs,
+                   reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
+  print_hard_reg_set (file, ";;     conflict hard regs:",
+                     conflicting_hard_regs);
   putc ('\n', file);
 }
 
 /* Print information about allocno or only regno (if REG_P) conflicts
+   to FILE.  */
+static void
+print_conflicts (FILE *file, bool reg_p)
+{
+  ira_allocno_t a;
+  ira_allocno_iterator ai;
+
+  FOR_EACH_ALLOCNO (a, ai)
+    print_allocno_conflicts (file, reg_p, a);
+}
+
+/* Print information about allocno or only regno (if REG_P) conflicts
    to stderr.  */
 void
 ira_debug_conflicts (bool reg_p)