]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ira-costs.c
c++: Handle multiple aggregate overloads [PR95319].
[thirdparty/gcc.git] / gcc / ira-costs.c
index 48ae264cd8fd2f9b29621978be73087569c5648a..6891156b5aaa6cdc7d43e536a74e077e216eef0c 100644 (file)
@@ -1,5 +1,5 @@
 /* IRA hard register and memory cost calculation for allocnos or pseudos.
-   Copyright (C) 2006-2014 Free Software Foundation, Inc.
+   Copyright (C) 2006-2020 Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
@@ -21,32 +21,19 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "hash-table.h"
-#include "hard-reg-set.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
-#include "expr.h"
-#include "tm_p.h"
-#include "flags.h"
+#include "tree.h"
 #include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "input.h"
-#include "function.h"
-#include "dominance.h"
-#include "cfg.h"
-#include "basic-block.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "insn-config.h"
 #include "regs.h"
+#include "ira.h"
+#include "ira-int.h"
 #include "addresses.h"
-#include "insn-config.h"
-#include "recog.h"
 #include "reload.h"
-#include "diagnostic-core.h"
-#include "target.h"
-#include "params.h"
-#include "ira-int.h"
 
 /* The flags is set up every time when we calculate pseudo register
    classes through function ira_set_pseudo_classes.  */
@@ -87,7 +74,7 @@ static struct costs *costs;
 static struct costs *total_allocno_costs;
 
 /* It is the current size of struct costs.  */
-static int struct_costs_size;
+static size_t struct_costs_size;
 
 /* Return pointer to structure containing costs of allocno or pseudo
    with given NUM in array ARR.  */
@@ -143,25 +130,23 @@ static cost_classes_t *regno_cost_classes;
 
 /* Helper for cost_classes hashing.  */
 
-struct cost_classes_hasher
+struct cost_classes_hasher : pointer_hash <cost_classes>
 {
-  typedef cost_classes value_type;
-  typedef cost_classes compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
-  static inline void remove (value_type *);
+  static inline hashval_t hash (const cost_classes *);
+  static inline bool equal (const cost_classes *, const cost_classes *);
+  static inline void remove (cost_classes *);
 };
 
 /* Returns hash value for cost classes info HV.  */
 inline hashval_t
-cost_classes_hasher::hash (const value_type *hv)
+cost_classes_hasher::hash (const cost_classes *hv)
 {
   return iterative_hash (&hv->classes, sizeof (enum reg_class) * hv->num, 0);
 }
 
 /* Compares cost classes info HV1 and HV2.  */
 inline bool
-cost_classes_hasher::equal (const value_type *hv1, const compare_type *hv2)
+cost_classes_hasher::equal (const cost_classes *hv1, const cost_classes *hv2)
 {
   return (hv1->num == hv2->num
          && memcmp (hv1->classes, hv2->classes,
@@ -170,7 +155,7 @@ cost_classes_hasher::equal (const value_type *hv1, const compare_type *hv2)
 
 /* Delete cost classes info V from the hash table.  */
 inline void
-cost_classes_hasher::remove (value_type *v)
+cost_classes_hasher::remove (cost_classes *v)
 {
   ira_free (v);
 }
@@ -185,6 +170,31 @@ static cost_classes_t cost_classes_aclass_cache[N_REG_CLASSES];
 /* Map mode -> cost classes for pseudo of give mode.  */
 static cost_classes_t cost_classes_mode_cache[MAX_MACHINE_MODE];
 
+/* Cost classes that include all classes in ira_important_classes.  */
+static cost_classes all_cost_classes;
+
+/* Use the array of classes in CLASSES_PTR to fill out the rest of
+   the structure.  */
+static void
+complete_cost_classes (cost_classes_t classes_ptr)
+{
+  for (int i = 0; i < N_REG_CLASSES; i++)
+    classes_ptr->index[i] = -1;
+  for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    classes_ptr->hard_regno_index[i] = -1;
+  for (int i = 0; i < classes_ptr->num; i++)
+    {
+      enum reg_class cl = classes_ptr->classes[i];
+      classes_ptr->index[cl] = i;
+      for (int j = ira_class_hard_regs_num[cl] - 1; j >= 0; j--)
+       {
+         unsigned int hard_regno = ira_class_hard_regs[cl][j];
+         if (classes_ptr->hard_regno_index[hard_regno] < 0)
+           classes_ptr->hard_regno_index[hard_regno] = i;
+       }
+    }
+}
+
 /* Initialize info about the cost classes for each pseudo.  */
 static void
 initiate_regno_cost_classes (void)
@@ -198,6 +208,10 @@ initiate_regno_cost_classes (void)
   memset (cost_classes_mode_cache, 0,
          sizeof (cost_classes_t) * MAX_MACHINE_MODE);
   cost_classes_htab = new hash_table<cost_classes_hasher> (200);
+  all_cost_classes.num = ira_important_classes_num;
+  for (int i = 0; i < ira_important_classes_num; i++)
+    all_cost_classes.classes[i] = ira_important_classes[i];
+  complete_cost_classes (&all_cost_classes);
 }
 
 /* Create new cost classes from cost classes FROM and set up members
@@ -209,27 +223,102 @@ static cost_classes_t
 setup_cost_classes (cost_classes_t from)
 {
   cost_classes_t classes_ptr;
-  enum reg_class cl;
-  int i, j, hard_regno;
 
   classes_ptr = (cost_classes_t) ira_allocate (sizeof (struct cost_classes));
   classes_ptr->num = from->num;
-  for (i = 0; i < N_REG_CLASSES; i++)
-    classes_ptr->index[i] = -1;
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    classes_ptr->hard_regno_index[i] = -1;
-  for (i = 0; i < from->num; i++)
+  for (int i = 0; i < from->num; i++)
+    classes_ptr->classes[i] = from->classes[i];
+  complete_cost_classes (classes_ptr);
+  return classes_ptr;
+}
+
+/* Return a version of FULL that only considers registers in REGS that are
+   valid for mode MODE.  Both FULL and the returned class are globally
+   allocated.  */
+static cost_classes_t
+restrict_cost_classes (cost_classes_t full, machine_mode mode,
+                      const_hard_reg_set regs)
+{
+  static struct cost_classes narrow;
+  int map[N_REG_CLASSES];
+  narrow.num = 0;
+  for (int i = 0; i < full->num; i++)
     {
-      cl = classes_ptr->classes[i] = from->classes[i];
-      classes_ptr->index[cl] = i;
-      for (j = ira_class_hard_regs_num[cl] - 1; j >= 0; j--)
+      /* Assume that we'll drop the class.  */
+      map[i] = -1;
+
+      /* Ignore classes that are too small for the mode.  */
+      enum reg_class cl = full->classes[i];
+      if (!contains_reg_of_mode[cl][mode])
+       continue;
+
+      /* Calculate the set of registers in CL that belong to REGS and
+        are valid for MODE.  */
+      HARD_REG_SET valid_for_cl = reg_class_contents[cl] & regs;
+      valid_for_cl &= ~(ira_prohibited_class_mode_regs[cl][mode]
+                       | ira_no_alloc_regs);
+      if (hard_reg_set_empty_p (valid_for_cl))
+       continue;
+
+      /* Don't use this class if the set of valid registers is a subset
+        of an existing class.  For example, suppose we have two classes
+        GR_REGS and FR_REGS and a union class GR_AND_FR_REGS.  Suppose
+        that the mode changes allowed by FR_REGS are not as general as
+        the mode changes allowed by GR_REGS.
+
+        In this situation, the mode changes for GR_AND_FR_REGS could
+        either be seen as the union or the intersection of the mode
+        changes allowed by the two subclasses.  The justification for
+        the union-based definition would be that, if you want a mode
+        change that's only allowed by GR_REGS, you can pick a register
+        from the GR_REGS subclass.  The justification for the
+        intersection-based definition would be that every register
+        from the class would allow the mode change.
+
+        However, if we have a register that needs to be in GR_REGS,
+        using GR_AND_FR_REGS with the intersection-based definition
+        would be too pessimistic, since it would bring in restrictions
+        that only apply to FR_REGS.  Conversely, if we have a register
+        that needs to be in FR_REGS, using GR_AND_FR_REGS with the
+        union-based definition would lose the extra restrictions
+        placed on FR_REGS.  GR_AND_FR_REGS is therefore only useful
+        for cases where GR_REGS and FP_REGS are both valid.  */
+      int pos;
+      for (pos = 0; pos < narrow.num; ++pos)
        {
-         hard_regno = ira_class_hard_regs[cl][j];
-         if (classes_ptr->hard_regno_index[hard_regno] < 0)
-           classes_ptr->hard_regno_index[hard_regno] = i;
+         enum reg_class cl2 = narrow.classes[pos];
+         if (hard_reg_set_subset_p (valid_for_cl, reg_class_contents[cl2]))
+           break;
+       }
+      map[i] = pos;
+      if (pos == narrow.num)
+       {
+         /* If several classes are equivalent, prefer to use the one
+            that was chosen as the allocno class.  */
+         enum reg_class cl2 = ira_allocno_class_translate[cl];
+         if (ira_class_hard_regs_num[cl] == ira_class_hard_regs_num[cl2])
+           cl = cl2;
+         narrow.classes[narrow.num++] = cl;
        }
     }
-  return classes_ptr;
+  if (narrow.num == full->num)
+    return full;
+
+  cost_classes **slot = cost_classes_htab->find_slot (&narrow, INSERT);
+  if (*slot == NULL)
+    {
+      cost_classes_t classes = setup_cost_classes (&narrow);
+      /* Map equivalent classes to the representative that we chose above.  */
+      for (int i = 0; i < ira_important_classes_num; i++)
+       {
+         enum reg_class cl = ira_important_classes[i];
+         int index = full->index[cl];
+         if (index >= 0)
+           classes->index[cl] = map[index];
+       }
+      *slot = classes;
+    }
+  return *slot;
 }
 
 /* Setup cost classes for pseudo REGNO whose allocno class is ACLASS.
@@ -251,8 +340,7 @@ setup_regno_cost_classes_by_aclass (int regno, enum reg_class aclass)
 
   if ((classes_ptr = cost_classes_aclass_cache[aclass]) == NULL)
     {
-      COPY_HARD_REG_SET (temp, reg_class_contents[aclass]);
-      AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
+      temp = reg_class_contents[aclass] & ~ira_no_alloc_regs;
       /* We exclude classes from consideration which are subsets of
         ACLASS only if ACLASS is an uniform class.  */
       exclude_p = ira_uniform_class_p[aclass];
@@ -264,8 +352,7 @@ setup_regno_cost_classes_by_aclass (int regno, enum reg_class aclass)
            {
              /* Exclude non-uniform classes which are subsets of
                 ACLASS.  */
-             COPY_HARD_REG_SET (temp2, reg_class_contents[cl]);
-             AND_COMPL_HARD_REG_SET (temp2, ira_no_alloc_regs);
+             temp2 = reg_class_contents[cl] & ~ira_no_alloc_regs;
              if (hard_reg_set_subset_p (temp2, temp) && cl != aclass)
                continue;
            }
@@ -279,48 +366,42 @@ setup_regno_cost_classes_by_aclass (int regno, enum reg_class aclass)
        }
       classes_ptr = cost_classes_aclass_cache[aclass] = (cost_classes_t) *slot;
     }
+  if (regno_reg_rtx[regno] != NULL_RTX)
+    {
+      /* Restrict the classes to those that are valid for REGNO's mode
+        (which might for example exclude singleton classes if the mode
+        requires two registers).  Also restrict the classes to those that
+        are valid for subregs of REGNO.  */
+      const HARD_REG_SET *valid_regs = valid_mode_changes_for_regno (regno);
+      if (!valid_regs)
+       valid_regs = &reg_class_contents[ALL_REGS];
+      classes_ptr = restrict_cost_classes (classes_ptr,
+                                          PSEUDO_REGNO_MODE (regno),
+                                          *valid_regs);
+    }
   regno_cost_classes[regno] = classes_ptr;
 }
 
 /* Setup cost classes for pseudo REGNO with MODE.  Usage of MODE can
    decrease number of cost classes for the pseudo, if hard registers
-   of some important classes can not hold a value of MODE.  So the
-   pseudo can not get hard register of some important classes and cost
+   of some important classes cannot hold a value of MODE.  So the
+   pseudo cannot get hard register of some important classes and cost
    calculation for such important classes is only wasting CPU
    time.  */
 static void
-setup_regno_cost_classes_by_mode (int regno, enum machine_mode mode)
+setup_regno_cost_classes_by_mode (int regno, machine_mode mode)
 {
-  static struct cost_classes classes;
-  cost_classes_t classes_ptr;
-  enum reg_class cl;
-  int i;
-  cost_classes **slot;
-  HARD_REG_SET temp;
-
-  if ((classes_ptr = cost_classes_mode_cache[mode]) == NULL)
+  if (const HARD_REG_SET *valid_regs = valid_mode_changes_for_regno (regno))
+    regno_cost_classes[regno] = restrict_cost_classes (&all_cost_classes,
+                                                      mode, *valid_regs);
+  else
     {
-      classes.num = 0;
-      for (i = 0; i < ira_important_classes_num; i++)
-       {
-         cl = ira_important_classes[i];
-         COPY_HARD_REG_SET (temp, ira_prohibited_class_mode_regs[cl][mode]);
-         IOR_HARD_REG_SET (temp, ira_no_alloc_regs);
-         if (hard_reg_set_subset_p (reg_class_contents[cl], temp))
-           continue;
-         classes.classes[classes.num++] = cl;
-       }
-      slot = cost_classes_htab->find_slot (&classes, INSERT);
-      if (*slot == NULL)
-       {
-         classes_ptr = setup_cost_classes (&classes);
-         *slot = classes_ptr;
-       }
-      else
-       classes_ptr = (cost_classes_t) *slot;
-      cost_classes_mode_cache[mode] = (cost_classes_t) *slot;
+      if (cost_classes_mode_cache[mode] == NULL)
+       cost_classes_mode_cache[mode]
+         = restrict_cost_classes (&all_cost_classes, mode,
+                                  reg_class_contents[ALL_REGS]);
+      regno_cost_classes[regno] = cost_classes_mode_cache[mode];
     }
-  regno_cost_classes[regno] = classes_ptr;
 }
 
 /* Finalize info about the cost classes for each pseudo.  */
@@ -338,7 +419,7 @@ finish_regno_cost_classes (void)
    TO_P is FALSE) a register of class RCLASS in mode MODE.  X must not
    be a pseudo register.  */
 static int
-copy_cost (rtx x, enum machine_mode mode, reg_class_t rclass, bool to_p,
+copy_cost (rtx x, machine_mode mode, reg_class_t rclass, bool to_p,
           secondary_reload_info *prev_sri)
 {
   secondary_reload_info sri;
@@ -357,6 +438,9 @@ copy_cost (rtx x, enum machine_mode mode, reg_class_t rclass, bool to_p,
      copy it.  */
   sri.prev_sri = prev_sri;
   sri.extra_cost = 0;
+  /* PR 68770: Secondary reload might examine the t_icode field.  */
+  sri.t_icode = CODE_FOR_nothing;
+
   secondary_class = targetm.secondary_reload (to_p, x, rclass, mode, &sri);
 
   if (secondary_class != NO_REGS)
@@ -411,7 +495,7 @@ copy_cost (rtx x, enum machine_mode mode, reg_class_t rclass, bool to_p,
    the alternatives.  */
 static void
 record_reg_classes (int n_alts, int n_ops, rtx *ops,
-                   enum machine_mode *modes, const char **constraints,
+                   machine_mode *modes, const char **constraints,
                    rtx_insn *insn, enum reg_class *pref)
 {
   int alt;
@@ -447,7 +531,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
          unsigned char c;
          const char *p = constraints[i];
          rtx op = ops[i];
-         enum machine_mode mode = modes[i];
+         machine_mode mode = modes[i];
          int allows_addr = 0;
          int win = 0;
 
@@ -472,7 +556,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
          while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
            p++;
 
-         if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
+         if (p[0] >= '0' && p[0] <= '0' + i)
            {
              /* Copy class and whether memory is allowed from the
                 matching alternative.  Then perform any needed cost
@@ -637,14 +721,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                      && ! find_reg_note (insn, REG_DEAD, op))
                    alt_cost += 2;
 
-                 /* This is in place of ordinary cost computation for
-                    this operand, so skip to the end of the
-                    alternative (should be just one character).  */
-                 while (*p && *p++ != ',')
-                   ;
-
-                 constraints[i] = p;
-                 continue;
+                 p++;
                }
            }
 
@@ -661,6 +738,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                  c = *++p;
                  break;
 
+               case '^':
+                 alt_cost += 2;
+                 break;
+
                case '?':
                  alt_cost += 2;
                  break;
@@ -698,6 +779,12 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                        win = 1;
                      break;
 
+                   case CT_SPECIAL_MEMORY:
+                     insn_allows_mem[i] = allows_mem[i] = 1;
+                     if (MEM_P (op) && constraint_satisfied_p (op, cn))
+                       win = 1;
+                     break;
+
                    case CT_ADDRESS:
                      /* Every address can be reloaded to fit.  */
                      allows_addr = 1;
@@ -728,6 +815,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 
          constraints[i] = p;
 
+         if (alt_fail)
+           break;
+
          /* How we account for this operand now depends on whether it
             is a pseudo register or not.  If it is, we first check if
             any register classes are valid.  If not, we ignore this
@@ -907,10 +997,21 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
            alt_cost += ira_memory_move_cost[mode][classes[i]][1];
          else
            alt_fail = 1;
+
+         if (alt_fail)
+           break;
        }
 
       if (alt_fail)
-       continue;
+       {
+         /* The loop above might have exited early once the failure
+            was seen.  Skip over the constraints for the remaining
+            operands.  */
+         i += 1;
+         for (; i < n_ops; ++i)
+           constraints[i] = skip_alternative (constraints[i]);
+         continue;
+       }
 
       op_cost_add = alt_cost * frequency;
       /* Finally, update the costs with the information we've
@@ -963,7 +1064,7 @@ ok_for_index_p_nonstrict (rtx reg)
    pseudo-registers should count as OK.  Arguments as for
    regno_ok_for_base_p.  */
 static inline bool
-ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
+ok_for_base_p_nonstrict (rtx reg, machine_mode mode, addr_space_t as,
                         enum rtx_code outer_code, enum rtx_code index_code)
 {
   unsigned regno = REGNO (reg);
@@ -986,7 +1087,7 @@ ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
    SCALE is twice the amount to multiply the cost by (it is twice so
    we can represent half-cost adjustments).  */
 static void
-record_address_regs (enum machine_mode mode, addr_space_t as, rtx x,
+record_address_regs (machine_mode mode, addr_space_t as, rtx x,
                     int context, enum rtx_code outer_code,
                     enum rtx_code index_code, int scale)
 {
@@ -1032,17 +1133,12 @@ record_address_regs (enum machine_mode mode, addr_space_t as, rtx x,
        if (code1 == SUBREG)
          arg1 = SUBREG_REG (arg1), code1 = GET_CODE (arg1);
 
-       /* If this machine only allows one register per address, it
-          must be in the first operand.  */
-       if (MAX_REGS_PER_ADDRESS == 1)
-         record_address_regs (mode, as, arg0, 0, PLUS, code1, scale);
-
-       /* If index and base registers are the same on this machine,
+       /* If index registers do not appear, or coincide with base registers,
           just record registers in any non-constant operands.  We
           assume here, as well as in the tests below, that all
           addresses are in canonical form.  */
-       else if (INDEX_REG_CLASS
-                == base_reg_class (VOIDmode, as, PLUS, SCRATCH))
+       if (MAX_REGS_PER_ADDRESS == 1
+           || INDEX_REG_CLASS == base_reg_class (VOIDmode, as, PLUS, SCRATCH))
          {
            record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
            if (! CONSTANT_P (arg1))
@@ -1156,7 +1252,7 @@ record_address_regs (enum machine_mode mode, addr_space_t as, rtx x,
            add_cost = (move_in_cost[i][rclass] * scale) / 2;
            if (INT_MAX - add_cost < pp_costs[k])
              pp_costs[k] = INT_MAX;
-           else 
+           else
              pp_costs[k] += add_cost;
          }
       }
@@ -1181,11 +1277,113 @@ static void
 record_operand_costs (rtx_insn *insn, enum reg_class *pref)
 {
   const char *constraints[MAX_RECOG_OPERANDS];
-  enum machine_mode modes[MAX_RECOG_OPERANDS];
-  rtx ops[MAX_RECOG_OPERANDS];
+  machine_mode modes[MAX_RECOG_OPERANDS];
   rtx set;
   int i;
 
+  if ((set = single_set (insn)) != NULL_RTX
+      /* In rare cases the single set insn might have less 2 operands
+        as the source can be a fixed special reg.  */
+      && recog_data.n_operands > 1
+      && recog_data.operand[0] == SET_DEST (set)
+      && recog_data.operand[1] == SET_SRC (set))
+    {
+      int regno, other_regno;
+      rtx dest = SET_DEST (set);
+      rtx src = SET_SRC (set);
+
+      if (GET_CODE (dest) == SUBREG
+         && known_eq (GET_MODE_SIZE (GET_MODE (dest)),
+                      GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))))
+       dest = SUBREG_REG (dest);
+      if (GET_CODE (src) == SUBREG
+         && known_eq (GET_MODE_SIZE (GET_MODE (src)),
+                      GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))))
+       src = SUBREG_REG (src);
+      if (REG_P (src) && REG_P (dest)
+         && (((regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
+              && (other_regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER)
+             || ((regno = REGNO (dest)) >= FIRST_PSEUDO_REGISTER
+                 && (other_regno = REGNO (src)) < FIRST_PSEUDO_REGISTER)))
+       {
+         machine_mode mode = GET_MODE (SET_SRC (set));
+         cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
+         enum reg_class *cost_classes = cost_classes_ptr->classes;
+         reg_class_t rclass, hard_reg_class, pref_class, bigger_hard_reg_class;
+         int cost, k;
+         move_table *move_costs;
+         bool dead_p = find_regno_note (insn, REG_DEAD, REGNO (src));
+
+         ira_init_register_move_cost_if_necessary (mode);
+         move_costs = ira_register_move_cost[mode];
+         hard_reg_class = REGNO_REG_CLASS (other_regno);
+         bigger_hard_reg_class = ira_pressure_class_translate[hard_reg_class];
+         /* Target code may return any cost for mode which does not
+            fit the hard reg class (e.g. DImode for AREG on
+            i386).  Check this and use a bigger class to get the
+            right cost.  */
+         if (bigger_hard_reg_class != NO_REGS
+             && ! ira_hard_reg_in_set_p (other_regno, mode,
+                                         reg_class_contents[hard_reg_class]))
+           hard_reg_class = bigger_hard_reg_class;
+         i = regno == (int) REGNO (src) ? 1 : 0;
+         for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+           {
+             rclass = cost_classes[k];
+             cost = (i == 0
+                     ? move_costs[hard_reg_class][rclass]
+                     : move_costs[rclass][hard_reg_class]);
+             
+             op_costs[i]->cost[k] = cost * 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
+                were not in the appropriate class.  */
+             if (pref)
+               {
+                 if ((pref_class = pref[COST_INDEX (regno)]) == NO_REGS)
+                   op_costs[i]->cost[k]
+                     += ((i == 0 ? ira_memory_move_cost[mode][rclass][0] : 0)
+                         + (i == 1 ? ira_memory_move_cost[mode][rclass][1] : 0)
+                         * frequency);
+                 else if (ira_reg_class_intersect[pref_class][rclass]
+                          == NO_REGS)
+                   op_costs[i]->cost[k]
+                     += (move_costs[pref_class][rclass]
+                         * frequency);
+               }
+             /* 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 then we
+                may want to adjust the cost of that register class to
+                -1.
+
+                Avoid the adjustment if the source does not die to
+                avoid stressing of register allocator by preferencing
+                two colliding registers into single class.  */
+             if (dead_p
+                 && TEST_HARD_REG_BIT (reg_class_contents[rclass], other_regno)
+                 && (reg_class_size[(int) rclass]
+                     == (ira_reg_class_max_nregs
+                         [(int) rclass][(int) GET_MODE(src)])))
+               {
+                 if (reg_class_size[rclass] == 1)
+                   op_costs[i]->cost[k] = -frequency;
+                 else if (in_hard_reg_set_p (reg_class_contents[rclass],
+                                             GET_MODE(src), other_regno))
+                   op_costs[i]->cost[k] = -frequency;
+               }
+           }
+         op_costs[i]->mem_cost
+           = ira_memory_move_cost[mode][hard_reg_class][i] * frequency;
+         if (pref && (pref_class = pref[COST_INDEX (regno)]) != NO_REGS)
+           op_costs[i]->mem_cost
+             += ira_memory_move_cost[mode][pref_class][i] * frequency;
+         return;
+       }
+    }
+
   for (i = 0; i < recog_data.n_operands; i++)
     {
       constraints[i] = recog_data.constraints[i];
@@ -1201,7 +1399,6 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
     {
       memcpy (op_costs[i], init_cost, struct_costs_size);
 
-      ops[i] = recog_data.operand[i];
       if (GET_CODE (recog_data.operand[i]) == SUBREG)
        recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
 
@@ -1217,7 +1414,7 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
                             recog_data.operand[i], 0, ADDRESS, SCRATCH,
                             frequency * 2);
     }
-  
+
   /* Check for commutative in a separate loop so everything will have
      been initialized.  We must do this even if one operand is a
      constant--see addsi3 in m68k.md.  */
@@ -1227,8 +1424,8 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
        const char *xconstraints[MAX_RECOG_OPERANDS];
        int j;
 
-       /* Handle commutative operands by swapping the constraints.
-          We assume the modes are the same.  */
+       /* Handle commutative operands by swapping the
+          constraints.  We assume the modes are the same.  */
        for (j = 0; j < recog_data.n_operands; j++)
          xconstraints[j] = constraints[j];
 
@@ -1241,80 +1438,6 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
   record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
                      recog_data.operand, modes,
                      constraints, insn, pref);
-
-  /* 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
-     then we may want to adjust the cost of that register class to -1.
-
-     Avoid the adjustment if the source does not die to avoid
-     stressing of register allocator by preferencing two colliding
-     registers into single class.
-
-     Also avoid the adjustment if a copy between hard registers of the
-     class is expensive (ten times the cost of a default copy is
-     considered arbitrarily expensive).  This avoids losing when the
-     preferred class is very expensive as the source of a copy
-     instruction.  */
-  if ((set = single_set (insn)) != NULL_RTX
-      /* In rare cases the single set insn might have less 2 operands
-        as the source can be a fixed special reg.  */
-      && recog_data.n_operands > 1
-      && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set))
-    {
-      int regno, other_regno;
-      rtx dest = SET_DEST (set);
-      rtx src = SET_SRC (set);
-
-      dest = SET_DEST (set);
-      src = SET_SRC (set);
-      if (GET_CODE (dest) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (dest))
-             == GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))))
-       dest = SUBREG_REG (dest);
-      if (GET_CODE (src) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (src))
-             == GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))))
-       src = SUBREG_REG (src);
-      if (REG_P (src) && REG_P (dest)
-         && find_regno_note (insn, REG_DEAD, REGNO (src))
-         && (((regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
-              && (other_regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER)
-             || ((regno = REGNO (dest)) >= FIRST_PSEUDO_REGISTER
-                 && (other_regno = REGNO (src)) < FIRST_PSEUDO_REGISTER)))
-       {
-         enum machine_mode mode = GET_MODE (src);
-         cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
-         enum reg_class *cost_classes = cost_classes_ptr->classes;
-         reg_class_t rclass;
-         int k, nr;
-
-         i = regno == (int) REGNO (src) ? 1 : 0;
-         for (k = cost_classes_ptr->num - 1; k >= 0; k--)
-           {
-             rclass = cost_classes[k];
-             if (TEST_HARD_REG_BIT (reg_class_contents[rclass], other_regno)
-                 && (reg_class_size[(int) rclass]
-                     == ira_reg_class_max_nregs [(int) rclass][(int) mode]))
-               {
-                 if (reg_class_size[rclass] == 1)
-                   op_costs[i]->cost[k] = -frequency;
-                 else
-                   {
-                     for (nr = 0;
-                          nr < hard_regno_nregs[other_regno][mode];
-                          nr++)
-                       if (! TEST_HARD_REG_BIT (reg_class_contents[rclass],
-                                                other_regno + nr))
-                         break;
-                     
-                     if (nr == hard_regno_nregs[other_regno][mode])
-                       op_costs[i]->cost[k] = -frequency;
-                   }
-               }
-           }
-       }
-    }
 }
 
 \f
@@ -1334,16 +1457,33 @@ scan_one_insn (rtx_insn *insn)
     return insn;
 
   pat_code = GET_CODE (PATTERN (insn));
-  if (pat_code == USE || pat_code == CLOBBER || pat_code == ASM_INPUT)
+  if (pat_code == ASM_INPUT)
     return insn;
 
+  /* If INSN is a USE/CLOBBER of a pseudo in a mode M then go ahead
+     and initialize the register move costs of mode M.
+
+     The pseudo may be related to another pseudo via a copy (implicit or
+     explicit) and if there are no mode M uses/sets of the original
+     pseudo, then we may leave the register move costs uninitialized for
+     mode M. */
+  if (pat_code == USE || pat_code == CLOBBER)
+    {
+      rtx x = XEXP (PATTERN (insn), 0);
+      if (GET_CODE (x) == REG
+         && REGNO (x) >= FIRST_PSEUDO_REGISTER
+         && have_regs_of_mode[GET_MODE (x)])
+        ira_init_register_move_cost_if_necessary (GET_MODE (x));
+      return insn;
+    }
+
   counted_mem = false;
   set = single_set (insn);
   extract_insn (insn);
 
   /* If this insn loads a parameter from its stack slot, then it
      represents a savings, rather than a cost, if the parameter is
-     stored in memory.  Record this fact. 
+     stored in memory.  Record this fact.
 
      Similarly if we're loading other constants from memory (constant
      pool, TOC references, small data areas, etc) and this is the only
@@ -1354,7 +1494,7 @@ scan_one_insn (rtx_insn *insn)
      mem_cost might result in it being loaded using the specialized
      instruction into a register, then stored into stack and loaded
      again from the stack.  See PR52208.
-     
+
      Don't do this if SET_SRC (set) has side effect.  See PR56124.  */
   if (set != 0 && REG_P (SET_DEST (set)) && MEM_P (SET_SRC (set))
       && (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != NULL_RTX
@@ -1364,7 +1504,10 @@ scan_one_insn (rtx_insn *insn)
              && targetm.legitimate_constant_p (GET_MODE (SET_DEST (set)),
                                                XEXP (note, 0))
              && REG_N_SETS (REGNO (SET_DEST (set))) == 1))
-      && general_operand (SET_SRC (set), GET_MODE (SET_SRC (set))))
+      && general_operand (SET_SRC (set), GET_MODE (SET_SRC (set)))
+      /* LRA does not use equiv with a symbol for PIC code.  */
+      && (! ira_use_lra_p || ! pic_offset_table_rtx
+         || ! contains_symbol_ref_p (XEXP (note, 0))))
     {
       enum reg_class cl = GENERAL_REGS;
       rtx reg = SET_DEST (set);
@@ -1384,36 +1527,40 @@ scan_one_insn (rtx_insn *insn)
   /* Now add the cost for each operand to the total costs for its
      allocno.  */
   for (i = 0; i < recog_data.n_operands; i++)
-    if (REG_P (recog_data.operand[i])
-       && REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER)
-      {
-       int regno = REGNO (recog_data.operand[i]);
-       struct costs *p = COSTS (costs, COST_INDEX (regno));
-       struct costs *q = op_costs[i];
-       int *p_costs = p->cost, *q_costs = q->cost;
-       cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
-       int add_cost;
-
-       /* If the already accounted for the memory "cost" above, don't
-          do so again.  */
-       if (!counted_mem)
-         {
-           add_cost = q->mem_cost;
-           if (add_cost > 0 && INT_MAX - add_cost < p->mem_cost)
-             p->mem_cost = INT_MAX;
-           else
-             p->mem_cost += add_cost;
-         }
-       for (k = cost_classes_ptr->num - 1; k >= 0; k--)
-         {
-           add_cost = q_costs[k];
-           if (add_cost > 0 && INT_MAX - add_cost < p_costs[k])
-             p_costs[k] = INT_MAX;
-           else
-             p_costs[k] += add_cost;
-         }
-      }
-
+    {
+      rtx op = recog_data.operand[i];
+      
+      if (GET_CODE (op) == SUBREG)
+       op = SUBREG_REG (op);
+      if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+       {
+         int regno = REGNO (op);
+         struct costs *p = COSTS (costs, COST_INDEX (regno));
+         struct costs *q = op_costs[i];
+         int *p_costs = p->cost, *q_costs = q->cost;
+         cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
+         int add_cost;
+         
+         /* If the already accounted for the memory "cost" above, don't
+            do so again.  */
+         if (!counted_mem)
+           {
+             add_cost = q->mem_cost;
+             if (add_cost > 0 && INT_MAX - add_cost < p->mem_cost)
+               p->mem_cost = INT_MAX;
+             else
+               p->mem_cost += add_cost;
+           }
+         for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+           {
+             add_cost = q_costs[k];
+             if (add_cost > 0 && INT_MAX - add_cost < p_costs[k])
+               p_costs[k] = INT_MAX;
+             else
+               p_costs[k] += add_cost;
+           }
+       }
+    }
   return insn;
 }
 
@@ -1447,15 +1594,11 @@ print_allocno_costs (FILE *f)
       for (k = 0; k < cost_classes_ptr->num; k++)
        {
          rclass = cost_classes[k];
-         if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
-             && ! invalid_mode_change_p (regno, (enum reg_class) rclass))
-           {
-             fprintf (f, " %s:%d", reg_class_names[rclass],
-                      COSTS (costs, i)->cost[k]);
-             if (flag_ira_region == IRA_REGION_ALL
-                 || flag_ira_region == IRA_REGION_MIXED)
-               fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]);
-           }
+         fprintf (f, " %s:%d", reg_class_names[rclass],
+                  COSTS (costs, i)->cost[k]);
+         if (flag_ira_region == IRA_REGION_ALL
+             || flag_ira_region == IRA_REGION_MIXED)
+           fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]);
        }
       fprintf (f, " MEM:%i", COSTS (costs, i)->mem_cost);
       if (flag_ira_region == IRA_REGION_ALL
@@ -1486,10 +1629,8 @@ print_pseudo_costs (FILE *f)
       for (k = 0; k < cost_classes_ptr->num; k++)
        {
          rclass = cost_classes[k];
-         if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
-             && ! invalid_mode_change_p (regno, (enum reg_class) rclass))
-           fprintf (f, " %s:%d", reg_class_names[rclass],
-                    COSTS (costs, regno)->cost[k]);
+         fprintf (f, " %s:%d", reg_class_names[rclass],
+                  COSTS (costs, regno)->cost[k]);
        }
       fprintf (f, " MEM:%i\n", COSTS (costs, regno)->mem_cost);
     }
@@ -1530,7 +1671,7 @@ find_costs_and_classes (FILE *dump_file)
   int i, k, start, max_cost_classes_num;
   int pass;
   basic_block bb;
-  enum reg_class *regno_best_class;
+  enum reg_class *regno_best_class, new_class;
 
   init_recog ();
   regno_best_class
@@ -1629,7 +1770,7 @@ find_costs_and_classes (FILE *dump_file)
          int best_cost, allocno_cost;
          enum reg_class best, alt_class;
          cost_classes_t cost_classes_ptr = regno_cost_classes[i];
-         enum reg_class *cost_classes = cost_classes_ptr->classes;
+         enum reg_class *cost_classes;
          int *i_costs = temp_costs->cost;
          int i_mem_cost;
          int equiv_savings = regno_equiv_gains[i];
@@ -1640,6 +1781,7 @@ find_costs_and_classes (FILE *dump_file)
                continue;
              memcpy (temp_costs, COSTS (costs, i), struct_costs_size);
              i_mem_cost = temp_costs->mem_cost;
+             cost_classes = cost_classes_ptr->classes;
            }
          else
            {
@@ -1647,13 +1789,14 @@ find_costs_and_classes (FILE *dump_file)
                continue;
              memset (temp_costs, 0, struct_costs_size);
              i_mem_cost = 0;
+             cost_classes = cost_classes_ptr->classes;
              /* Find cost of all allocnos with the same regno.  */
              for (a = ira_regno_allocno_map[i];
                   a != NULL;
                   a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
                {
                  int *a_costs, *p_costs;
-                     
+
                  a_num = ALLOCNO_NUM (a);
                  if ((flag_ira_region == IRA_REGION_ALL
                       || flag_ira_region == IRA_REGION_MIXED)
@@ -1726,11 +1869,6 @@ find_costs_and_classes (FILE *dump_file)
          for (k = 0; k < cost_classes_ptr->num; k++)
            {
              rclass = cost_classes[k];
-             /* Ignore classes that are too small or invalid for this
-                operand.  */
-             if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
-                 || invalid_mode_change_p (i, (enum reg_class) rclass))
-               continue;
              if (i_costs[k] < best_cost)
                {
                  best_cost = i_costs[k];
@@ -1752,7 +1890,8 @@ find_costs_and_classes (FILE *dump_file)
                alt_class = reg_class_subunion[alt_class][rclass];
            }
          alt_class = ira_allocno_class_translate[alt_class];
-         if (best_cost > i_mem_cost)
+         if (best_cost > i_mem_cost
+             && ! non_spilled_static_chain_regno_p (i))
            regno_aclass[i] = NO_REGS;
          else if (!optimize && !targetm.class_likely_spilled_p (best))
            /* Registers in the alternative class are likely to need
@@ -1766,20 +1905,40 @@ find_costs_and_classes (FILE *dump_file)
               short in -O0 code and so register pressure tends to be low.
 
               Avoid that by ignoring the alternative class if the best
-              class has plenty of registers.  */
-           regno_aclass[i] = best;
+              class has plenty of registers.
+
+              The union class arrays give important classes and only
+              part of it are allocno classes.  So translate them into
+              allocno classes.  */
+           regno_aclass[i] = ira_allocno_class_translate[best];
          else
            {
              /* Make the common class the biggest class of best and
-                alt_class.  */
-             regno_aclass[i]
-               = ira_reg_class_superunion[best][alt_class];
+                alt_class.  Translate the common class into an
+                allocno class too.  */
+             regno_aclass[i] = (ira_allocno_class_translate
+                                [ira_reg_class_superunion[best][alt_class]]);
              ira_assert (regno_aclass[i] != NO_REGS
                          && ira_reg_allocno_class_p[regno_aclass[i]]);
            }
+         if ((new_class
+              = (reg_class) (targetm.ira_change_pseudo_allocno_class
+                             (i, regno_aclass[i], best))) != regno_aclass[i])
+           {
+             regno_aclass[i] = new_class;
+             if (hard_reg_set_subset_p (reg_class_contents[new_class],
+                                        reg_class_contents[best]))
+               best = new_class;
+             if (hard_reg_set_subset_p (reg_class_contents[new_class],
+                                        reg_class_contents[alt_class]))
+               alt_class = new_class;
+           }
          if (pass == flag_expensive_optimizations)
            {
-             if (best_cost > i_mem_cost)
+             if (best_cost > i_mem_cost
+                 /* Do not assign NO_REGS to static chain pointer
+                    pseudo when non-local goto is used.  */
+                 && ! non_spilled_static_chain_regno_p (i))
                best = alt_class = NO_REGS;
              else if (best == alt_class)
                alt_class = NO_REGS;
@@ -1794,7 +1953,9 @@ find_costs_and_classes (FILE *dump_file)
          regno_best_class[i] = best;
          if (! allocno_p)
            {
-             pref[i] = best_cost > i_mem_cost ? NO_REGS : best;
+             pref[i] = (best_cost > i_mem_cost
+                        && ! non_spilled_static_chain_regno_p (i)
+                        ? NO_REGS : best);
              continue;
            }
          for (a = ira_regno_allocno_map[i];
@@ -1805,7 +1966,7 @@ find_costs_and_classes (FILE *dump_file)
              int a_num = ALLOCNO_NUM (a);
              int *total_a_costs = COSTS (total_allocno_costs, a_num)->cost;
              int *a_costs = COSTS (costs, a_num)->cost;
-       
+
              if (aclass == NO_REGS)
                best = NO_REGS;
              else
@@ -1820,12 +1981,7 @@ find_costs_and_classes (FILE *dump_file)
                      rclass = cost_classes[k];
                      if (! ira_class_subset_p[rclass][aclass])
                        continue;
-                     /* Ignore classes that are too small or invalid
-                        for this operand.  */
-                     if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
-                         || invalid_mode_change_p (i, (enum reg_class) rclass))
-                       ;
-                     else if (total_a_costs[k] < best_cost)
+                     if (total_a_costs[k] < best_cost)
                        {
                          best_cost = total_a_costs[k];
                          allocno_cost = a_costs[k];
@@ -1872,7 +2028,7 @@ find_costs_and_classes (FILE *dump_file)
                }
            }
        }
-      
+
       if (internal_flag_ira_verbose > 4 && dump_file)
        {
          if (allocno_p)
@@ -1939,6 +2095,13 @@ process_bb_node_for_hard_reg_moves (ira_loop_tree_node_t loop_tree_node)
        }
       else
        continue;
+      if (reg_class_size[(int) REGNO_REG_CLASS (hard_regno)]
+         == (ira_reg_class_max_nregs
+             [REGNO_REG_CLASS (hard_regno)][(int) ALLOCNO_MODE(a)]))
+       /* If the class can provide only one hard reg to the allocno,
+          we processed the insn record_operand_costs already and we
+          actually updated the hard reg cost there.  */
+       continue;
       rclass = ALLOCNO_CLASS (a);
       if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], hard_regno))
        continue;
@@ -1954,8 +2117,8 @@ process_bb_node_for_hard_reg_moves (ira_loop_tree_node_t loop_tree_node)
       {
        int cost;
        enum reg_class hard_reg_class;
-       enum machine_mode mode;
-       
+       machine_mode mode;
+
        mode = ALLOCNO_MODE (a);
        hard_reg_class = REGNO_REG_CLASS (hard_regno);
        ira_init_register_move_cost_if_necessary (mode);
@@ -2164,13 +2327,12 @@ ira_tune_allocno_costs (void)
   int j, n, regno;
   int cost, min_cost, *reg_costs;
   enum reg_class aclass, rclass;
-  enum machine_mode mode;
+  machine_mode mode;
   ira_allocno_t a;
   ira_allocno_iterator ai;
   ira_allocno_object_iterator oi;
   ira_object_t obj;
   bool skip_p;
-  HARD_REG_SET *crossed_calls_clobber_regs;
 
   FOR_EACH_ALLOCNO (a, ai)
     {
@@ -2205,13 +2367,7 @@ ira_tune_allocno_costs (void)
                continue;
              rclass = REGNO_REG_CLASS (regno);
              cost = 0;
-             crossed_calls_clobber_regs
-               = &(ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a));
-             if (ira_hard_reg_set_intersection_p (regno, mode,
-                                                  *crossed_calls_clobber_regs)
-                 && (ira_hard_reg_set_intersection_p (regno, mode,
-                                                      call_used_reg_set)
-                     || HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+             if (ira_need_caller_save_p (a, regno))
                cost += (ALLOCNO_CALL_FREQ (a)
                         * (ira_memory_move_cost[mode][rclass][0]
                            + ira_memory_move_cost[mode][rclass][1]));
@@ -2271,3 +2427,9 @@ ira_adjust_equiv_reg_cost (unsigned regno, int cost)
   else
     regno_equiv_gains[regno] += cost;
 }
+
+void
+ira_costs_c_finalize (void)
+{
+  this_target_ira_int->free_ira_costs ();
+}