]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ira-color.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / ira-color.c
index 8a90ae1b4e6c10c2efa3239a48cd7b4edb7e5950..3d01c60800c5dd666d9581c0adbcfff02872fb75 100644 (file)
@@ -1,5 +1,5 @@
 /* IRA allocation based on graph coloring.
-   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+   Copyright (C) 2006-2021 Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
@@ -151,6 +151,8 @@ struct allocno_color_data
   ira_allocno_t next_thread_allocno;
   /* All thread frequency.  Defined only for first thread allocno.  */
   int thread_freq;
+  /* Sum of frequencies of hard register preferences of the allocno.  */
+  int hard_reg_prefs;
 };
 
 /* See above.  */
@@ -218,7 +220,7 @@ inline bool
 allocno_hard_regs_hasher::equal (const allocno_hard_regs *hv1,
                                 const allocno_hard_regs *hv2)
 {
-  return hard_reg_set_equal_p (hv1->set, hv2->set);
+  return hv1->set == hv2->set;
 }
 
 /* Hash table of unique allocno hard registers.  */
@@ -261,14 +263,14 @@ add_allocno_hard_regs (HARD_REG_SET set, int64_t cost)
   allocno_hard_regs_t hv;
 
   gcc_assert (! hard_reg_set_empty_p (set));
-  COPY_HARD_REG_SET (temp.set, set);
+  temp.set = set;
   if ((hv = find_hard_regs (&temp)) != NULL)
     hv->cost += cost;
   else
     {
       hv = ((struct allocno_hard_regs *)
            ira_allocate (sizeof (struct allocno_hard_regs)));
-      COPY_HARD_REG_SET (hv->set, set);
+      hv->set = set;
       hv->cost = cost;
       allocno_hard_regs_vec.safe_push (hv);
       insert_hard_regs (hv);
@@ -371,7 +373,7 @@ add_allocno_hard_regs_to_forest (allocno_hard_regs_node_t *roots,
   start = hard_regs_node_vec.length ();
   for (node = *roots; node != NULL; node = node->next)
     {
-      if (hard_reg_set_equal_p (hv->set, node->hard_regs->set))
+      if (hv->set == node->hard_regs->set)
        return;
       if (hard_reg_set_subset_p (hv->set, node->hard_regs->set))
        {
@@ -382,8 +384,7 @@ add_allocno_hard_regs_to_forest (allocno_hard_regs_node_t *roots,
        hard_regs_node_vec.safe_push (node);
       else if (hard_reg_set_intersect_p (hv->set, node->hard_regs->set))
        {
-         COPY_HARD_REG_SET (temp_set, hv->set);
-         AND_HARD_REG_SET (temp_set, node->hard_regs->set);
+         temp_set = hv->set & node->hard_regs->set;
          hv2 = add_allocno_hard_regs (temp_set, hv->cost);
          add_allocno_hard_regs_to_forest (&node->first, hv2);
        }
@@ -398,7 +399,7 @@ add_allocno_hard_regs_to_forest (allocno_hard_regs_node_t *roots,
           i++)
        {
          node = hard_regs_node_vec[i];
-         IOR_HARD_REG_SET (temp_set, node->hard_regs->set);
+         temp_set |= node->hard_regs->set;
        }
       hv = add_allocno_hard_regs (temp_set, hv->cost);
       new_node = create_new_allocno_hard_regs_node (hv);
@@ -479,24 +480,26 @@ first_common_ancestor_node (allocno_hard_regs_node_t first,
 static void
 print_hard_reg_set (FILE *f, HARD_REG_SET set, bool new_line_p)
 {
-  int i, start;
+  int i, start, end;
 
-  for (start = -1, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  for (start = end = -1, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      if (TEST_HARD_REG_BIT (set, i))
+      bool reg_included = TEST_HARD_REG_BIT (set, i);
+
+      if (reg_included)
        {
-         if (i == 0 || ! TEST_HARD_REG_BIT (set, i - 1))
+         if (start == -1)
            start = i;
+         end = i;
        }
-      if (start >= 0
-         && (i == FIRST_PSEUDO_REGISTER - 1 || ! TEST_HARD_REG_BIT (set, i)))
+      if (start >= 0 && (!reg_included || i == FIRST_PSEUDO_REGISTER - 1))
        {
-         if (start == i - 1)
+         if (start == end)
            fprintf (f, " %d", start);
-         else if (start == i - 2)
-           fprintf (f, " %d %d", start, start + 1);
+         else if (start == end + 1)
+           fprintf (f, " %d %d", start, end);
          else
-           fprintf (f, " %d-%d", start, i - 1);
+           fprintf (f, " %d-%d", start, end);
          start = -1;
        }
     }
@@ -717,8 +720,7 @@ form_allocno_hard_regs_nodes_forest (void)
            (allocno_data->profitable_hard_regs,
             ALLOCNO_MEMORY_COST (a) - ALLOCNO_CLASS_COST (a)));
     }
-  SET_HARD_REG_SET (temp);
-  AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
+  temp = ~ira_no_alloc_regs;
   add_allocno_hard_regs (temp, 0);
   qsort (allocno_hard_regs_vec.address () + start,
         allocno_hard_regs_vec.length () - start,
@@ -833,10 +835,10 @@ setup_left_conflict_sizes_p (ira_allocno_t a)
   nobj = ALLOCNO_NUM_OBJECTS (a);
   data = ALLOCNO_COLOR_DATA (a);
   subnodes = allocno_hard_regs_subnodes + data->hard_regs_subnodes_start;
-  COPY_HARD_REG_SET (profitable_hard_regs, data->profitable_hard_regs);
+  profitable_hard_regs = data->profitable_hard_regs;
   node = data->hard_regs_node;
   node_preorder_num = node->preorder_num;
-  COPY_HARD_REG_SET (node_set, node->hard_regs->set);
+  node_set = node->hard_regs->set;
   node_check_tick++;
   for (k = 0; k < nobj; k++)
     {
@@ -859,7 +861,7 @@ setup_left_conflict_sizes_p (ira_allocno_t a)
                                             ->profitable_hard_regs))
            continue;
          conflict_node = conflict_data->hard_regs_node;
-         COPY_HARD_REG_SET (conflict_node_set, conflict_node->hard_regs->set);
+         conflict_node_set = conflict_node->hard_regs->set;
          if (hard_reg_set_subset_p (node_set, conflict_node_set))
            temp_node = node;
          else
@@ -897,8 +899,7 @@ setup_left_conflict_sizes_p (ira_allocno_t a)
          int j, n, hard_regno;
          enum reg_class aclass;
          
-         COPY_HARD_REG_SET (temp_set, temp_node->hard_regs->set);
-         AND_HARD_REG_SET (temp_set, profitable_hard_regs);
+         temp_set = temp_node->hard_regs->set & profitable_hard_regs;
          aclass = ALLOCNO_CLASS (a);
          for (n = 0, j = ira_class_hard_regs_num[aclass] - 1; j >= 0; j--)
            {
@@ -1042,15 +1043,15 @@ setup_profitable_hard_regs (void)
       else
        {
          mode = ALLOCNO_MODE (a);
-         COPY_HARD_REG_SET (data->profitable_hard_regs,
-                            ira_useful_class_mode_regs[aclass][mode]);
+         data->profitable_hard_regs
+           = ira_useful_class_mode_regs[aclass][mode];
          nobj = ALLOCNO_NUM_OBJECTS (a);
          for (k = 0; k < nobj; k++)
            {
              ira_object_t obj = ALLOCNO_OBJECT (a, k);
              
-             AND_COMPL_HARD_REG_SET (data->profitable_hard_regs,
-                                     OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+             data->profitable_hard_regs
+               &= ~OBJECT_TOTAL_CONFLICT_HARD_REGS (obj);
            }
        }
     }
@@ -1091,9 +1092,8 @@ setup_profitable_hard_regs (void)
                       hard_regno + num);
                }
              else
-               AND_COMPL_HARD_REG_SET
-                 (ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs,
-                  ira_reg_mode_hard_regset[hard_regno][mode]);
+               ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs
+                 &= ~ira_reg_mode_hard_regset[hard_regno][mode];
            }
        }
     }
@@ -1199,6 +1199,10 @@ struct update_cost_queue_elem
      connecting this allocno to the one being allocated.  */
   int divisor;
 
+  /* Allocno from which we started chaining costs of connected
+     allocnos. */
+  ira_allocno_t start;
+
   /* Allocno from which we are chaining costs of connected allocnos.
      It is used not go back in graph of allocnos connected by
      copies.  */
@@ -1258,10 +1262,11 @@ start_update_cost (void)
   update_cost_queue = NULL;
 }
 
-/* Add (ALLOCNO, FROM, DIVISOR) to the end of update_cost_queue, unless
+/* Add (ALLOCNO, START, FROM, DIVISOR) to the end of update_cost_queue, unless
    ALLOCNO is already in the queue, or has NO_REGS class.  */
 static inline void
-queue_update_cost (ira_allocno_t allocno, ira_allocno_t from, int divisor)
+queue_update_cost (ira_allocno_t allocno, ira_allocno_t start,
+                  ira_allocno_t from, int divisor)
 {
   struct update_cost_queue_elem *elem;
 
@@ -1270,6 +1275,7 @@ queue_update_cost (ira_allocno_t allocno, ira_allocno_t from, int divisor)
       && ALLOCNO_CLASS (allocno) != NO_REGS)
     {
       elem->check = update_cost_check;
+      elem->start = start;
       elem->from = from;
       elem->divisor = divisor;
       elem->next = NULL;
@@ -1282,10 +1288,11 @@ queue_update_cost (ira_allocno_t allocno, ira_allocno_t from, int divisor)
 }
 
 /* Try to remove the first element from update_cost_queue.  Return
-   false if the queue was empty, otherwise make (*ALLOCNO, *FROM,
-   *DIVISOR) describe the removed element.  */
+   false if the queue was empty, otherwise make (*ALLOCNO, *START,
+   *FROM, *DIVISOR) describe the removed element.  */
 static inline bool
-get_next_update_cost (ira_allocno_t *allocno, ira_allocno_t *from, int *divisor)
+get_next_update_cost (ira_allocno_t *allocno, ira_allocno_t *start,
+                     ira_allocno_t *from, int *divisor)
 {
   struct update_cost_queue_elem *elem;
 
@@ -1294,6 +1301,7 @@ get_next_update_cost (ira_allocno_t *allocno, ira_allocno_t *from, int *divisor)
 
   *allocno = update_cost_queue;
   elem = &update_cost_queue_elems[ALLOCNO_NUM (*allocno)];
+  *start = elem->start;
   *from = elem->from;
   *divisor = elem->divisor;
   update_cost_queue = elem->next;
@@ -1325,10 +1333,31 @@ update_allocno_cost (ira_allocno_t allocno, int hard_regno,
   return true;
 }
 
+/* Return TRUE if allocnos A1 and A2 conflicts. Here we are
+   interesting only in conflicts of allocnos with intersected allocno
+   classes. */
+static bool
+allocnos_conflict_p (ira_allocno_t a1, ira_allocno_t a2)
+{
+  ira_object_t obj, conflict_obj;
+  ira_object_conflict_iterator oci;
+  int word, nwords = ALLOCNO_NUM_OBJECTS (a1);
+  
+  for (word = 0; word < nwords; word++)
+    {
+      obj = ALLOCNO_OBJECT (a1, word);
+      /* Take preferences of conflicting allocnos into account.  */
+      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+       if (OBJECT_ALLOCNO (conflict_obj) == a2)
+         return true;
+    }
+  return false;
+}  
+
 /* Update (decrease if DECR_P) HARD_REGNO cost of allocnos connected
    by copies to ALLOCNO to increase chances to remove some copies as
-   the result of subsequent assignment.  Record cost updates if
-   RECORD_P is true.  */
+   the result of subsequent assignment.  Update conflict costs.
+   Record cost updates if RECORD_P is true.  */
 static void
 update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
                           int divisor, bool decr_p, bool record_p)
@@ -1336,7 +1365,7 @@ update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
   int cost, update_cost, update_conflict_cost;
   machine_mode mode;
   enum reg_class rclass, aclass;
-  ira_allocno_t another_allocno, from = NULL;
+  ira_allocno_t another_allocno, start = allocno, from = NULL;
   ira_copy_t cp, next_cp;
 
   rclass = REGNO_REG_CLASS (hard_regno);
@@ -1359,7 +1388,10 @@ update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
          else
            gcc_unreachable ();
 
-         if (another_allocno == from)
+         if (another_allocno == from
+             || (ALLOCNO_COLOR_DATA (another_allocno) != NULL
+                 && (ALLOCNO_COLOR_DATA (allocno)->first_thread_allocno
+                     != ALLOCNO_COLOR_DATA (another_allocno)->first_thread_allocno)))
            continue;
 
          aclass = ALLOCNO_CLASS (another_allocno);
@@ -1375,30 +1407,33 @@ update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
             register classes bigger modes might be invalid,
             e.g. DImode for AREG on x86.  For such cases the
             register move cost will be maximal.  */
-         mode = narrower_subreg_mode (mode, ALLOCNO_MODE (cp->second));
-         
+         mode = narrower_subreg_mode (ALLOCNO_MODE (cp->first),
+                                      ALLOCNO_MODE (cp->second));
+
+         ira_init_register_move_cost_if_necessary (mode);
+
          cost = (cp->second == allocno
                  ? ira_register_move_cost[mode][rclass][aclass]
                  : ira_register_move_cost[mode][aclass][rclass]);
          if (decr_p)
            cost = -cost;
 
-         update_conflict_cost = update_cost = cp->freq * cost / divisor;
-
-         if (ALLOCNO_COLOR_DATA (another_allocno) != NULL
-             && (ALLOCNO_COLOR_DATA (allocno)->first_thread_allocno
-                 != ALLOCNO_COLOR_DATA (another_allocno)->first_thread_allocno))
-           /* Decrease conflict cost of ANOTHER_ALLOCNO if it is not
-              in the same allocation thread.  */
-           update_conflict_cost /= COST_HOP_DIVISOR;
+         update_cost = cp->freq * cost / divisor;
+         update_conflict_cost = update_cost;
 
+         if (internal_flag_ira_verbose > 5 && ira_dump_file != NULL)
+           fprintf (ira_dump_file,
+                    "          a%dr%d (hr%d): update cost by %d, conflict cost by %d\n",
+                    ALLOCNO_NUM (another_allocno), ALLOCNO_REGNO (another_allocno),
+                    hard_regno, update_cost, update_conflict_cost);
          if (update_cost == 0)
            continue;
 
          if (! update_allocno_cost (another_allocno, hard_regno,
                                     update_cost, update_conflict_cost))
            continue;
-         queue_update_cost (another_allocno, allocno, divisor * COST_HOP_DIVISOR);
+         queue_update_cost (another_allocno, start, allocno,
+                            divisor * COST_HOP_DIVISOR);
          if (record_p && ALLOCNO_COLOR_DATA (another_allocno) != NULL)
            ALLOCNO_COLOR_DATA (another_allocno)->update_cost_records
              = get_update_cost_record (hard_regno, divisor,
@@ -1406,7 +1441,7 @@ update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
                                        ->update_cost_records);
        }
     }
-  while (get_next_update_cost (&allocno, &from, &divisor));
+  while (get_next_update_cost (&allocno, &start, &from, &divisor));
 }
 
 /* Decrease preferred ALLOCNO hard register costs and costs of
@@ -1418,8 +1453,13 @@ update_costs_from_prefs (ira_allocno_t allocno)
 
   start_update_cost ();
   for (pref = ALLOCNO_PREFS (allocno); pref != NULL; pref = pref->next_pref)
-    update_costs_from_allocno (allocno, pref->hard_regno,
-                              COST_HOP_DIVISOR, true, true);
+    {
+      if (internal_flag_ira_verbose > 5 && ira_dump_file != NULL)
+       fprintf (ira_dump_file, "        Start updating from pref of hr%d for a%dr%d:\n",
+                pref->hard_regno, ALLOCNO_NUM (allocno), ALLOCNO_REGNO (allocno));
+      update_costs_from_allocno (allocno, pref->hard_regno,
+                                COST_HOP_DIVISOR, true, true);
+    }
 }
 
 /* Update (decrease if DECR_P) the cost of allocnos connected to
@@ -1434,6 +1474,9 @@ update_costs_from_copies (ira_allocno_t allocno, bool decr_p, bool record_p)
   hard_regno = ALLOCNO_HARD_REGNO (allocno);
   ira_assert (hard_regno >= 0 && ALLOCNO_CLASS (allocno) != NO_REGS);
   start_update_cost ();
+  if (internal_flag_ira_verbose > 5 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "        Start updating from a%dr%d by copies:\n",
+            ALLOCNO_NUM (allocno), ALLOCNO_REGNO (allocno));
   update_costs_from_allocno (allocno, hard_regno, 1, decr_p, record_p);
 }
 
@@ -1482,6 +1525,9 @@ restore_costs_from_copies (ira_allocno_t allocno)
     return;
   records = ALLOCNO_COLOR_DATA (allocno)->update_cost_records;
   start_update_cost ();
+  if (internal_flag_ira_verbose > 5 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "        Start restoring from a%dr%d:\n",
+            ALLOCNO_NUM (allocno), ALLOCNO_REGNO (allocno));
   for (curr = records; curr != NULL; curr = curr->next)
     update_costs_from_allocno (allocno, curr->hard_regno,
                               curr->divisor, true, false);
@@ -1502,10 +1548,10 @@ update_conflict_hard_regno_costs (int *costs, enum reg_class aclass,
   int *conflict_costs;
   bool cont_p;
   enum reg_class another_aclass;
-  ira_allocno_t allocno, another_allocno, from;
+  ira_allocno_t allocno, another_allocno, start, from;
   ira_copy_t cp, next_cp;
 
-  while (get_next_update_cost (&allocno, &from, &divisor))
+  while (get_next_update_cost (&allocno, &start, &from, &divisor))
     for (cp = ALLOCNO_COPIES (allocno); cp != NULL; cp = next_cp)
       {
        if (cp->first == allocno)
@@ -1521,7 +1567,8 @@ update_conflict_hard_regno_costs (int *costs, enum reg_class aclass,
        else
          gcc_unreachable ();
 
-       if (another_allocno == from)
+       if (another_allocno == from
+           || allocnos_conflict_p (another_allocno, start))
          continue;
 
        another_aclass = ALLOCNO_CLASS (another_allocno);
@@ -1567,7 +1614,7 @@ update_conflict_hard_regno_costs (int *costs, enum reg_class aclass,
                           * COST_HOP_DIVISOR
                           * COST_HOP_DIVISOR
                           * COST_HOP_DIVISOR))
-         queue_update_cost (another_allocno, allocno, divisor * COST_HOP_DIVISOR);
+         queue_update_cost (another_allocno, start, from, divisor * COST_HOP_DIVISOR);
       }
 }
 
@@ -1589,20 +1636,15 @@ get_conflict_and_start_profitable_regs (ira_allocno_t a, bool retry_p,
   for (i = 0; i < nwords; i++)
     {
       obj = ALLOCNO_OBJECT (a, i);
-      COPY_HARD_REG_SET (conflict_regs[i],
-                        OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+      conflict_regs[i] = OBJECT_TOTAL_CONFLICT_HARD_REGS (obj);
     }
   if (retry_p)
-    {
-      COPY_HARD_REG_SET (*start_profitable_regs,
-                        reg_class_contents[ALLOCNO_CLASS (a)]);
-      AND_COMPL_HARD_REG_SET (*start_profitable_regs,
-                             ira_prohibited_class_mode_regs
-                             [ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)]);
-    }
+    *start_profitable_regs
+      = (reg_class_contents[ALLOCNO_CLASS (a)]
+        &~ (ira_prohibited_class_mode_regs
+            [ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)]));
   else
-    COPY_HARD_REG_SET (*start_profitable_regs,
-                      ALLOCNO_COLOR_DATA (a)->profitable_hard_regs);
+    *start_profitable_regs = ALLOCNO_COLOR_DATA (a)->profitable_hard_regs;
 }
 
 /* Return true if HARD_REGNO is ok for assigning to allocno A with
@@ -1659,7 +1701,7 @@ calculate_saved_nregs (int hard_regno, machine_mode mode)
   ira_assert (hard_regno >= 0);
   for (i = hard_regno_nregs (hard_regno, mode) - 1; i >= 0; i--)
     if (!allocated_hardreg_p[hard_regno + i]
-       && !TEST_HARD_REG_BIT (call_used_reg_set, hard_regno + i)
+       && !crtl->abi->clobbers_full_reg_p (hard_regno + i)
        && !LOCAL_REGNO (hard_regno + i))
       nregs++;
   return nregs;
@@ -1803,9 +1845,8 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
                                          hard_regno + num);
                    }
                  else
-                   IOR_HARD_REG_SET
-                     (conflicting_regs[word],
-                      ira_reg_mode_hard_regset[hard_regno][mode]);
+                   conflicting_regs[word]
+                     |= ira_reg_mode_hard_regset[hard_regno][mode];
                  if (hard_reg_set_subset_p (profitable_hard_regs,
                                             conflicting_regs[word]))
                    goto fail;
@@ -1842,8 +1883,7 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
                      continue;
                    full_costs[j] -= conflict_costs[k];
                  }
-             queue_update_cost (conflict_a, NULL, COST_HOP_DIVISOR);
-
+             queue_update_cost (conflict_a, conflict_a, NULL, COST_HOP_DIVISOR);
            }
        }
     }
@@ -1857,7 +1897,7 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
   if (! retry_p)
     {
       start_update_cost ();
-      queue_update_cost (a, NULL,  COST_HOP_DIVISOR);
+      queue_update_cost (a, a, NULL, COST_HOP_DIVISOR);
       update_conflict_hard_regno_costs (full_costs, aclass, false);
     }
   min_cost = min_full_cost = INT_MAX;
@@ -1902,7 +1942,11 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
          best_hard_regno = hard_regno;
          ira_assert (hard_regno >= 0);
        }
+      if (internal_flag_ira_verbose > 5 && ira_dump_file != NULL)
+       fprintf (ira_dump_file, "(%d=%d,%d) ", hard_regno, cost, full_cost);
     }
+  if (internal_flag_ira_verbose > 5 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "\n");
   if (min_full_cost > mem_cost
       /* Do not spill static chain pointer pseudo when non-local goto
         is used.  */
@@ -2081,7 +2125,7 @@ form_threads_from_copies (int cp_num)
              if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
                fprintf
                  (ira_dump_file,
-                  "      Forming thread by copy %d:a%dr%d-a%dr%d (freq=%d):\n",
+                  "        Forming thread by copy %d:a%dr%d-a%dr%d (freq=%d):\n",
                   cp->num, ALLOCNO_NUM (cp->first), ALLOCNO_REGNO (cp->first),
                   ALLOCNO_NUM (cp->second), ALLOCNO_REGNO (cp->second),
                   cp->freq);
@@ -2089,7 +2133,7 @@ form_threads_from_copies (int cp_num)
              if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
                {
                  thread1 = ALLOCNO_COLOR_DATA (thread1)->first_thread_allocno;
-                 fprintf (ira_dump_file, "        Result (freq=%d): a%dr%d(%d)",
+                 fprintf (ira_dump_file, "          Result (freq=%d): a%dr%d(%d)",
                           ALLOCNO_COLOR_DATA (thread1)->thread_freq,
                           ALLOCNO_NUM (thread1), ALLOCNO_REGNO (thread1),
                           ALLOCNO_FREQ (thread1));
@@ -2153,6 +2197,9 @@ form_threads_from_colorable_allocno (ira_allocno_t a)
   ira_copy_t cp, next_cp;
   int cp_num = 0;
 
+  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "      Forming thread from allocno a%dr%d:\n",
+            ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
   for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
     {
       if (cp->first == a)
@@ -2182,6 +2229,7 @@ init_allocno_threads (void)
   ira_allocno_t a;
   unsigned int j;
   bitmap_iterator bi;
+  ira_pref_t pref;
 
   EXECUTE_IF_SET_IN_BITMAP (consideration_allocno_bitmap, 0, j, bi)
     {
@@ -2190,6 +2238,9 @@ init_allocno_threads (void)
       ALLOCNO_COLOR_DATA (a)->first_thread_allocno
        = ALLOCNO_COLOR_DATA (a)->next_thread_allocno = a;
       ALLOCNO_COLOR_DATA (a)->thread_freq = ALLOCNO_FREQ (a);
+      ALLOCNO_COLOR_DATA (a)->hard_reg_prefs = 0;
+      for (pref = ALLOCNO_PREFS (a); pref != NULL; pref = pref->next_pref)
+       ALLOCNO_COLOR_DATA (a)->hard_reg_prefs += pref->freq;
     }
 }
 
@@ -2470,7 +2521,13 @@ remove_allocno_from_bucket_and_push (ira_allocno_t allocno, bool colorable_p)
 static void
 push_only_colorable (void)
 {
+  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "      Forming thread from colorable bucket:\n");
   form_threads_from_bucket (colorable_allocno_bucket);
+  for (ira_allocno_t a = colorable_allocno_bucket;
+       a != NULL;
+       a = ALLOCNO_COLOR_DATA (a)->next_bucket_allocno)
+    update_costs_from_prefs (a);
   sort_bucket (&colorable_allocno_bucket, bucket_allocno_compare_func);
   for (;colorable_allocno_bucket != NULL;)
     remove_allocno_from_bucket_and_push (colorable_allocno_bucket, true);
@@ -2484,7 +2541,6 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
   int freq, i;
   edge_iterator ei;
   edge e;
-  vec<edge> edges;
 
   ira_assert (current_loops != NULL && loop_node->loop != NULL
              && (regno < 0 || regno >= FIRST_PSEUDO_REGISTER));
@@ -2500,13 +2556,12 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
     }
   else
     {
-      edges = get_loop_exit_edges (loop_node->loop);
+      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
       FOR_EACH_VEC_ELT (edges, i, e)
        if (regno < 0
            || (bitmap_bit_p (df_get_live_out (e->src), regno)
                && bitmap_bit_p (df_get_live_in (e->dest), regno)))
          freq += EDGE_FREQUENCY (e);
-      edges.release ();
     }
 
   return REG_FREQ_FROM_EDGE_FREQ (freq);
@@ -2652,7 +2707,7 @@ pop_allocnos_from_stack (void)
       else if (assign_hard_reg (allocno, false))
        {
          if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
-           fprintf (ira_dump_file, "assign reg %d\n",
+           fprintf (ira_dump_file, "        assign reg %d\n",
                     ALLOCNO_HARD_REGNO (allocno));
        }
       else if (ALLOCNO_ASSIGNED_P (allocno))
@@ -2698,8 +2753,7 @@ setup_allocno_available_regs_num (ira_allocno_t a)
      reg_class_names[aclass], ira_class_hard_regs_num[aclass], n);
   print_hard_reg_set (ira_dump_file, data->profitable_hard_regs, false);
   fprintf (ira_dump_file, ", %snode: ",
-          hard_reg_set_equal_p (data->profitable_hard_regs,
-                                data->hard_regs_node->hard_regs->set)
+          data->profitable_hard_regs == data->hard_regs_node->hard_regs->set
           ? "" : "^");
   print_hard_reg_set (ira_dump_file,
                      data->hard_regs_node->hard_regs->set, false);
@@ -2828,6 +2882,7 @@ allocno_copy_cost_saving (ira_allocno_t allocno, int hard_regno)
        }
       else
        gcc_unreachable ();
+      ira_init_register_move_cost_if_necessary (allocno_mode);
       cost += cp->freq * ira_register_move_cost[allocno_mode][rclass][rclass];
     }
   return cost;
@@ -3167,7 +3222,6 @@ color_allocnos (void)
          if (ALLOCNO_CLASS (a) != NO_REGS && ! empty_profitable_hard_regs (a))
            {
              ALLOCNO_COLOR_DATA (a)->in_graph_p = true;
-             update_costs_from_prefs (a);
              update_conflict_allocno_hard_prefs (a);
            }
          else
@@ -4387,11 +4441,10 @@ allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs)
   for (i = 0; i < n; i++)
     {
       ira_object_t obj = ALLOCNO_OBJECT (a, i);
-      COPY_HARD_REG_SET (saved[i], OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
-      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), forbidden_regs);
+      saved[i] = OBJECT_TOTAL_CONFLICT_HARD_REGS (obj);
+      OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= forbidden_regs;
       if (! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
-       IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
-                         call_used_reg_set);
+       OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= ira_need_caller_save_regs (a);
     }
   ALLOCNO_ASSIGNED_P (a) = false;
   aclass = ALLOCNO_CLASS (a);
@@ -4410,9 +4463,7 @@ allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs)
               ? ALLOCNO_CLASS_COST (a)
               : ALLOCNO_HARD_REG_COSTS (a)[ira_class_hard_reg_index
                                            [aclass][hard_regno]]));
-      if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0
-         && ira_hard_reg_set_intersection_p (hard_regno, ALLOCNO_MODE (a),
-                                             call_used_reg_set))
+      if (ira_need_caller_save_p (a, hard_regno))
        {
          ira_assert (flag_caller_saves);
          caller_save_needed = 1;
@@ -4434,7 +4485,7 @@ allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs)
   for (i = 0; i < n; i++)
     {
       ira_object_t obj = ALLOCNO_OBJECT (a, i);
-      COPY_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), saved[i]);
+      OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) = saved[i];
     }
   return reg_renumber[regno] >= 0;
 }
@@ -4519,9 +4570,9 @@ ira_reassign_pseudos (int *spilled_pseudo_regs, int num,
   for (i = 0; i < num; i++)
     {
       regno = spilled_pseudo_regs[i];
-      COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
-      IOR_HARD_REG_SET (forbidden_regs, pseudo_forbidden_regs[regno]);
-      IOR_HARD_REG_SET (forbidden_regs, pseudo_previous_regs[regno]);
+      forbidden_regs = (bad_spill_regs
+                       | pseudo_forbidden_regs[regno]
+                       | pseudo_previous_regs[regno]);
       gcc_assert (reg_renumber[regno] < 0);
       a = ira_regno_allocno_map[regno];
       ira_mark_allocation_change (regno);
@@ -4557,7 +4608,7 @@ ira_reuse_stack_slot (int regno, poly_uint64 inherent_size,
   ira_allocno_t another_allocno, allocno = ira_regno_allocno_map[regno];
   rtx x;
   bitmap_iterator bi;
-  struct ira_spilled_reg_stack_slot *slot = NULL;
+  class ira_spilled_reg_stack_slot *slot = NULL;
 
   ira_assert (! ira_use_lra_p);
 
@@ -4669,7 +4720,7 @@ ira_reuse_stack_slot (int regno, poly_uint64 inherent_size,
 void
 ira_mark_new_stack_slot (rtx x, int regno, poly_uint64 total_size)
 {
-  struct ira_spilled_reg_stack_slot *slot;
+  class ira_spilled_reg_stack_slot *slot;
   int slot_num;
   ira_allocno_t allocno;
 
@@ -4699,16 +4750,16 @@ ira_mark_new_stack_slot (rtx x, int regno, poly_uint64 total_size)
    given IN and OUT for INSN.  Return also number points (through
    EXCESS_PRESSURE_LIVE_LENGTH) where the pseudo-register lives and
    the register pressure is high, number of references of the
-   pseudo-registers (through NREFS), number of callee-clobbered
-   hard-registers occupied by the pseudo-registers (through
-   CALL_USED_COUNT), and the first hard regno occupied by the
+   pseudo-registers (through NREFS), the number of psuedo registers
+   whose allocated register wouldn't need saving in the prologue
+   (through CALL_USED_COUNT), and the first hard regno occupied by the
    pseudo-registers (through FIRST_HARD_REGNO).  */
 static int
 calculate_spill_cost (int *regnos, rtx in, rtx out, rtx_insn *insn,
                      int *excess_pressure_live_length,
                      int *nrefs, int *call_used_count, int *first_hard_regno)
 {
-  int i, cost, regno, hard_regno, j, count, saved_cost, nregs;
+  int i, cost, regno, hard_regno, count, saved_cost;
   bool in_p, out_p;
   int length;
   ira_allocno_t a;
@@ -4725,11 +4776,8 @@ calculate_spill_cost (int *regnos, rtx in, rtx out, rtx_insn *insn,
       a = ira_regno_allocno_map[regno];
       length += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) / ALLOCNO_NUM_OBJECTS (a);
       cost += ALLOCNO_MEMORY_COST (a) - ALLOCNO_CLASS_COST (a);
-      nregs = hard_regno_nregs (hard_regno, ALLOCNO_MODE (a));
-      for (j = 0; j < nregs; j++)
-       if (! TEST_HARD_REG_BIT (call_used_reg_set, hard_regno + j))
-         break;
-      if (j == nregs)
+      if (in_hard_reg_set_p (crtl->abi->full_reg_clobbers (),
+                            ALLOCNO_MODE (a), hard_regno))
        count++;
       in_p = in && REG_P (in) && (int) REGNO (in) == hard_regno;
       out_p = out && REG_P (out) && (int) REGNO (out) == hard_regno;
@@ -4886,11 +4934,10 @@ fast_allocation (void)
       for (l = 0; l < nr; l++)
        {
          ira_object_t obj = ALLOCNO_OBJECT (a, l);
-         IOR_HARD_REG_SET (conflict_hard_regs,
-                           OBJECT_CONFLICT_HARD_REGS (obj));
+         conflict_hard_regs |= OBJECT_CONFLICT_HARD_REGS (obj);
          for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
            for (j = r->start; j <= r->finish; j++)
-             IOR_HARD_REG_SET (conflict_hard_regs, used_hard_regs[j]);
+             conflict_hard_regs |= used_hard_regs[j];
        }
       aclass = ALLOCNO_CLASS (a);
       ALLOCNO_ASSIGNED_P (a) = true;
@@ -4938,8 +4985,7 @@ fast_allocation (void)
          ira_object_t obj = ALLOCNO_OBJECT (a, l);
          for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
            for (k = r->start; k <= r->finish; k++)
-             IOR_HARD_REG_SET (used_hard_regs[k],
-                               ira_reg_mode_hard_regset[hard_regno][mode]);
+             used_hard_regs[k] |= ira_reg_mode_hard_regset[hard_regno][mode];
        }
     }
   ira_free (sorted_allocnos);