]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ira-conflicts.c
rs6000: New iterator CCEITHER
[thirdparty/gcc.git] / gcc / ira-conflicts.c
index fc2e842660836c1075cded263c046d6d8b0f5a26..9a3e3811dbd93d98f66c757955ddad06d2cc3fe8 100644 (file)
@@ -1,6 +1,5 @@
 /* IRA conflict builder.
 /* IRA conflict builder.
-   Copyright (C) 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
@@ -22,22 +21,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "regs.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
 #include "rtl.h"
+#include "predict.h"
+#include "memmodel.h"
 #include "tm_p.h"
 #include "tm_p.h"
-#include "target.h"
-#include "flags.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
 #include "insn-config.h"
 #include "insn-config.h"
-#include "recog.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
+#include "regs.h"
+#include "ira.h"
+#include "ira-int.h"
 #include "params.h"
 #include "params.h"
-#include "df.h"
 #include "sparseset.h"
 #include "sparseset.h"
-#include "ira-int.h"
 #include "addresses.h"
 
 /* This file contains code responsible for allocno conflict creation,
 #include "addresses.h"
 
 /* This file contains code responsible for allocno conflict creation,
@@ -48,11 +43,11 @@ along with GCC; see the file COPYING3.  If not see
    allocno's conflict (can't go in the same hardware register).
 
    Some arrays will be used as conflict bit vector of the
    allocno's conflict (can't go in the same hardware register).
 
    Some arrays will be used as conflict bit vector of the
-   corresponding allocnos see function build_allocno_conflicts.  */
+   corresponding allocnos see function build_object_conflicts.  */
 static IRA_INT_TYPE **conflicts;
 
 /* Macro to test a conflict of C1 and C2 in `conflicts'.  */
 static IRA_INT_TYPE **conflicts;
 
 /* Macro to test a conflict of C1 and C2 in `conflicts'.  */
-#define OBJECTS_CONFLICT_P(C1, C2)                             \
+#define OBJECTS_CONFLICT_P(C1, C2)                                     \
   (OBJECT_MIN (C1) <= OBJECT_CONFLICT_ID (C2)                          \
    && OBJECT_CONFLICT_ID (C2) <= OBJECT_MAX (C1)                       \
    && TEST_MINMAX_SET_BIT (conflicts[OBJECT_CONFLICT_ID (C1)],         \
   (OBJECT_MIN (C1) <= OBJECT_CONFLICT_ID (C2)                          \
    && OBJECT_CONFLICT_ID (C2) <= OBJECT_MAX (C1)                       \
    && TEST_MINMAX_SET_BIT (conflicts[OBJECT_CONFLICT_ID (C1)],         \
@@ -60,6 +55,36 @@ static IRA_INT_TYPE **conflicts;
                           OBJECT_MIN (C1), OBJECT_MAX (C1)))
 
 \f
                           OBJECT_MIN (C1), OBJECT_MAX (C1)))
 
 \f
+/* Record a conflict between objects OBJ1 and OBJ2.  If necessary,
+   canonicalize the conflict by recording it for lower-order subobjects
+   of the corresponding allocnos.  */
+static void
+record_object_conflict (ira_object_t obj1, ira_object_t obj2)
+{
+  ira_allocno_t a1 = OBJECT_ALLOCNO (obj1);
+  ira_allocno_t a2 = OBJECT_ALLOCNO (obj2);
+  int w1 = OBJECT_SUBWORD (obj1);
+  int w2 = OBJECT_SUBWORD (obj2);
+  int id1, id2;
+
+  /* Canonicalize the conflict.  If two identically-numbered words
+     conflict, always record this as a conflict between words 0.  That
+     is the only information we need, and it is easier to test for if
+     it is collected in each allocno's lowest-order object.  */
+  if (w1 == w2 && w1 > 0)
+    {
+      obj1 = ALLOCNO_OBJECT (a1, 0);
+      obj2 = ALLOCNO_OBJECT (a2, 0);
+    }
+  id1 = OBJECT_CONFLICT_ID (obj1);
+  id2 = OBJECT_CONFLICT_ID (obj2);
+
+  SET_MINMAX_SET_BIT (conflicts[id1], id2, OBJECT_MIN (obj1),
+                     OBJECT_MAX (obj1));
+  SET_MINMAX_SET_BIT (conflicts[id2], id1, OBJECT_MIN (obj2),
+                     OBJECT_MAX (obj2));
+}
+
 /* Build allocno conflict table by processing allocno live ranges.
    Return true if the table was built.  The table is not built if it
    is too big.  */
 /* Build allocno conflict table by processing allocno live ranges.
    Return true if the table was built.  The table is not built if it
    is too big.  */
@@ -68,57 +93,59 @@ build_conflict_bit_table (void)
 {
   int i;
   unsigned int j;
 {
   int i;
   unsigned int j;
-  enum reg_class cover_class;
+  enum reg_class aclass;
   int object_set_words, allocated_words_num, conflict_bit_vec_words_num;
   live_range_t r;
   ira_allocno_t allocno;
   ira_allocno_iterator ai;
   sparseset objects_live;
   int object_set_words, allocated_words_num, conflict_bit_vec_words_num;
   live_range_t r;
   ira_allocno_t allocno;
   ira_allocno_iterator ai;
   sparseset objects_live;
+  ira_object_t obj;
+  ira_allocno_object_iterator aoi;
 
   allocated_words_num = 0;
   FOR_EACH_ALLOCNO (allocno, ai)
 
   allocated_words_num = 0;
   FOR_EACH_ALLOCNO (allocno, ai)
-    {
-      ira_object_t obj = ALLOCNO_OBJECT (allocno);
-      if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
+    FOR_EACH_ALLOCNO_OBJECT (allocno, obj, aoi)
+      {
+       if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
          continue;
          continue;
-      conflict_bit_vec_words_num
-       = ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
-          / IRA_INT_BITS);
-      allocated_words_num += conflict_bit_vec_words_num;
-      if ((unsigned long long) allocated_words_num * sizeof (IRA_INT_TYPE)
-         > (unsigned long long) IRA_MAX_CONFLICT_TABLE_SIZE * 1024 * 1024)
-       {
-         if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
-           fprintf
-             (ira_dump_file,
-              "+++Conflict table will be too big(>%dMB) -- don't use it\n",
-              IRA_MAX_CONFLICT_TABLE_SIZE);
-         return false;
-       }
-    }
+       conflict_bit_vec_words_num
+         = ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
+            / IRA_INT_BITS);
+       allocated_words_num += conflict_bit_vec_words_num;
+       if ((uint64_t) allocated_words_num * sizeof (IRA_INT_TYPE)
+           > (uint64_t) IRA_MAX_CONFLICT_TABLE_SIZE * 1024 * 1024)
+         {
+           if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+             fprintf
+               (ira_dump_file,
+                "+++Conflict table will be too big(>%dMB) -- don't use it\n",
+                IRA_MAX_CONFLICT_TABLE_SIZE);
+           return false;
+         }
+      }
 
   conflicts = (IRA_INT_TYPE **) ira_allocate (sizeof (IRA_INT_TYPE *)
                                              * ira_objects_num);
   allocated_words_num = 0;
   FOR_EACH_ALLOCNO (allocno, ai)
 
   conflicts = (IRA_INT_TYPE **) ira_allocate (sizeof (IRA_INT_TYPE *)
                                              * ira_objects_num);
   allocated_words_num = 0;
   FOR_EACH_ALLOCNO (allocno, ai)
-    {
-      ira_object_t obj = ALLOCNO_OBJECT (allocno);
-      int id = OBJECT_CONFLICT_ID (obj);
-      if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
-       {
-         conflicts[id] = NULL;
-         continue;
-       }
-      conflict_bit_vec_words_num
-       = ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
-          / IRA_INT_BITS);
-      allocated_words_num += conflict_bit_vec_words_num;
-      conflicts[id]
-       = (IRA_INT_TYPE *) ira_allocate (sizeof (IRA_INT_TYPE)
-                                        * conflict_bit_vec_words_num);
-      memset (conflicts[id], 0,
-             sizeof (IRA_INT_TYPE) * conflict_bit_vec_words_num);
-    }
+    FOR_EACH_ALLOCNO_OBJECT (allocno, obj, aoi)
+      {
+       int id = OBJECT_CONFLICT_ID (obj);
+       if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
+         {
+           conflicts[id] = NULL;
+           continue;
+         }
+       conflict_bit_vec_words_num
+         = ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
+            / IRA_INT_BITS);
+       allocated_words_num += conflict_bit_vec_words_num;
+       conflicts[id]
+         = (IRA_INT_TYPE *) ira_allocate (sizeof (IRA_INT_TYPE)
+                                          * conflict_bit_vec_words_num);
+       memset (conflicts[id], 0,
+               sizeof (IRA_INT_TYPE) * conflict_bit_vec_words_num);
+      }
 
   object_set_words = (ira_objects_num + IRA_INT_BITS - 1) / IRA_INT_BITS;
   if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
 
   object_set_words = (ira_objects_num + IRA_INT_BITS - 1) / IRA_INT_BITS;
   if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
@@ -137,33 +164,27 @@ build_conflict_bit_table (void)
          ira_allocno_t allocno = OBJECT_ALLOCNO (obj);
          int id = OBJECT_CONFLICT_ID (obj);
 
          ira_allocno_t allocno = OBJECT_ALLOCNO (obj);
          int id = OBJECT_CONFLICT_ID (obj);
 
-         cover_class = ALLOCNO_COVER_CLASS (allocno);
-         sparseset_set_bit (objects_live, id);
+         gcc_assert (id < ira_objects_num);
+
+         aclass = ALLOCNO_CLASS (allocno);
          EXECUTE_IF_SET_IN_SPARSESET (objects_live, j)
            {
          EXECUTE_IF_SET_IN_SPARSESET (objects_live, j)
            {
-             ira_object_t live_cr = ira_object_id_map[j];
-             ira_allocno_t live_a = OBJECT_ALLOCNO (live_cr);
-             enum reg_class live_cover_class = ALLOCNO_COVER_CLASS (live_a);
+             ira_object_t live_obj = ira_object_id_map[j];
+             ira_allocno_t live_a = OBJECT_ALLOCNO (live_obj);
+             enum reg_class live_aclass = ALLOCNO_CLASS (live_a);
 
 
-             if (ira_reg_classes_intersect_p[cover_class][live_cover_class]
+             if (ira_reg_classes_intersect_p[aclass][live_aclass]
                  /* Don't set up conflict for the allocno with itself.  */
                  /* Don't set up conflict for the allocno with itself.  */
-                 && id != (int) j)
+                 && live_a != allocno)
                {
                {
-                 SET_MINMAX_SET_BIT (conflicts[id], j,
-                                     OBJECT_MIN (obj),
-                                     OBJECT_MAX (obj));
-                 SET_MINMAX_SET_BIT (conflicts[j], id,
-                                     OBJECT_MIN (live_cr),
-                                     OBJECT_MAX (live_cr));
+                 record_object_conflict (obj, live_obj);
                }
            }
                }
            }
+         sparseset_set_bit (objects_live, id);
        }
 
       for (r = ira_finish_point_ranges[i]; r != NULL; r = r->finish_next)
        }
 
       for (r = ira_finish_point_ranges[i]; r != NULL; r = r->finish_next)
-       {
-         ira_object_t obj = r->object;
-         sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (obj));
-       }
+       sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (r->object));
     }
   sparseset_free (objects_live);
   return true;
     }
   sparseset_free (objects_live);
   return true;
@@ -173,151 +194,15 @@ build_conflict_bit_table (void)
    register due to conflicts.  */
 
 static bool
    register due to conflicts.  */
 
 static bool
-allocnos_conflict_p (ira_allocno_t a1, ira_allocno_t a2)
+allocnos_conflict_for_copy_p (ira_allocno_t a1, ira_allocno_t a2)
 {
 {
-  ira_object_t obj1 = ALLOCNO_OBJECT (a1);
-  ira_object_t obj2 = ALLOCNO_OBJECT (a2);
-  return OBJECTS_CONFLICT_P (obj1, obj2);
-}
-
-/* Return TRUE if the operand constraint STR is commutative.  */
-static bool
-commutative_constraint_p (const char *str)
-{
-  bool ignore_p;
-  int c;
-
-  for (ignore_p = false;;)
-    {
-      c = *str;
-      if (c == '\0')
-       break;
-      str += CONSTRAINT_LEN (c, str);
-      if (c == '#')
-       ignore_p = true;
-      else if (c == ',')
-       ignore_p = false;
-      else if (! ignore_p)
-       {
-         /* Usually `%' is the first constraint character but the
-            documentation does not require this.  */
-         if (c == '%')
-           return true;
-       }
-    }
-  return false;
-}
+  /* Due to the fact that we canonicalize conflicts (see
+     record_object_conflict), we only need to test for conflicts of
+     the lowest order words.  */
+  ira_object_t obj1 = ALLOCNO_OBJECT (a1, 0);
+  ira_object_t obj2 = ALLOCNO_OBJECT (a2, 0);
 
 
-/* Return the number of the operand which should be the same in any
-   case as operand with number OP_NUM (or negative value if there is
-   no such operand).  If USE_COMMUT_OP_P is TRUE, the function makes
-   temporarily commutative operand exchange before this.  The function
-   takes only really possible alternatives into consideration.  */
-static int
-get_dup_num (int op_num, bool use_commut_op_p)
-{
-  int curr_alt, c, original, dup;
-  bool ignore_p, commut_op_used_p;
-  const char *str;
-  rtx op;
-
-  if (op_num < 0 || recog_data.n_alternatives == 0)
-    return -1;
-  op = recog_data.operand[op_num];
-  commut_op_used_p = true;
-  if (use_commut_op_p)
-    {
-      if (commutative_constraint_p (recog_data.constraints[op_num]))
-       op_num++;
-      else if (op_num > 0 && commutative_constraint_p (recog_data.constraints
-                                                      [op_num - 1]))
-       op_num--;
-      else
-       commut_op_used_p = false;
-    }
-  str = recog_data.constraints[op_num];
-  for (ignore_p = false, original = -1, curr_alt = 0;;)
-    {
-      c = *str;
-      if (c == '\0')
-       break;
-      if (c == '#')
-       ignore_p = true;
-      else if (c == ',')
-       {
-         curr_alt++;
-         ignore_p = false;
-       }
-      else if (! ignore_p)
-       switch (c)
-         {
-         case 'X':
-           return -1;
-
-         case 'm':
-         case 'o':
-           /* Accept a register which might be placed in memory.  */
-           return -1;
-           break;
-
-         case 'V':
-         case '<':
-         case '>':
-           break;
-
-         case 'p':
-           if (address_operand (op, VOIDmode))
-             return -1;
-           break;
-
-         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':
-         case 'q': case 't': case 'u':
-         case 'v': case 'w': case 'x': case 'y': case 'z':
-         case 'A': case 'B': case 'C': case 'D':
-         case 'Q': case 'R': case 'S': case 'T': case 'U':
-         case 'W': case 'Y': case 'Z':
-           {
-             enum reg_class cl;
-
-             cl = (c == 'r'
-                   ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, str));
-             if (cl != NO_REGS)
-               return -1;
-#ifdef EXTRA_CONSTRAINT_STR
-             else if (EXTRA_CONSTRAINT_STR (op, c, str))
-               return -1;
-#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)
-             return -1;
-           original = c;
-           break;
-         }
-      str += CONSTRAINT_LEN (c, str);
-    }
-  if (original == -1)
-    return -1;
-  dup = original - '0';
-  if (use_commut_op_p)
-    {
-      if (commutative_constraint_p (recog_data.constraints[dup]))
-       dup++;
-      else if (dup > 0
-              && commutative_constraint_p (recog_data.constraints[dup -1]))
-       dup--;
-      else if (! commut_op_used_p)
-       return -1;
-    }
-  return dup;
+  return OBJECTS_CONFLICT_P (obj1, obj2);
 }
 
 /* Check that X is REG or SUBREG of REG.  */
 }
 
 /* Check that X is REG or SUBREG of REG.  */
@@ -341,8 +226,11 @@ go_through_subreg (rtx x, int *offset)
   if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
     *offset = subreg_regno_offset (REGNO (reg), GET_MODE (reg),
                                   SUBREG_BYTE (x), GET_MODE (x));
   if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
     *offset = subreg_regno_offset (REGNO (reg), GET_MODE (reg),
                                   SUBREG_BYTE (x), GET_MODE (x));
-  else
-    *offset = (SUBREG_BYTE (x) / REGMODE_NATURAL_SIZE (GET_MODE (x)));
+  else if (!can_div_trunc_p (SUBREG_BYTE (x),
+                            REGMODE_NATURAL_SIZE (GET_MODE (x)), offset))
+    /* Checked by validate_subreg.  We must know at compile time which
+       inner hard registers are being accessed.  */
+    gcc_unreachable ();
   return reg;
 }
 
   return reg;
 }
 
@@ -356,13 +244,13 @@ go_through_subreg (rtx x, int *offset)
    FALSE.  */
 static bool
 process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
    FALSE.  */
 static bool
 process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
-                      rtx insn, int freq)
+                      rtx_insn *insn, int freq)
 {
   int allocno_preferenced_hard_regno, cost, index, offset1, offset2;
   bool only_regs_p;
   ira_allocno_t a;
 {
   int allocno_preferenced_hard_regno, cost, index, offset1, offset2;
   bool only_regs_p;
   ira_allocno_t a;
-  enum reg_class rclass, cover_class;
-  enum machine_mode mode;
+  reg_class_t rclass, aclass;
+  machine_mode mode;
   ira_copy_t cp;
 
   gcc_assert (REG_SUBREG_P (reg1) && REG_SUBREG_P (reg2));
   ira_copy_t cp;
 
   gcc_assert (REG_SUBREG_P (reg1) && REG_SUBREG_P (reg2));
@@ -387,7 +275,8 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
     {
       ira_allocno_t a1 = ira_curr_regno_allocno_map[REGNO (reg1)];
       ira_allocno_t a2 = ira_curr_regno_allocno_map[REGNO (reg2)];
     {
       ira_allocno_t a1 = ira_curr_regno_allocno_map[REGNO (reg1)];
       ira_allocno_t a2 = ira_curr_regno_allocno_map[REGNO (reg2)];
-      if (!allocnos_conflict_p (a1, a2) && offset1 == offset2)
+
+      if (!allocnos_conflict_for_copy_p (a1, a2) && offset1 == offset2)
        {
          cp = ira_add_allocno_copy (a1, a2, freq, constraint_p, insn,
                                     ira_curr_loop_tree_node);
        {
          cp = ira_add_allocno_copy (a1, a2, freq, constraint_p, insn,
                                     ira_curr_loop_tree_node);
@@ -398,35 +287,38 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
        return false;
     }
 
        return false;
     }
 
-  if (! IN_RANGE (allocno_preferenced_hard_regno, 0, FIRST_PSEUDO_REGISTER - 1))
-    /* Can not be tied.  */
+  if (! IN_RANGE (allocno_preferenced_hard_regno,
+                 0, FIRST_PSEUDO_REGISTER - 1))
+    /* Cannot be tied.  */
     return false;
   rclass = REGNO_REG_CLASS (allocno_preferenced_hard_regno);
   mode = ALLOCNO_MODE (a);
     return false;
   rclass = REGNO_REG_CLASS (allocno_preferenced_hard_regno);
   mode = ALLOCNO_MODE (a);
-  cover_class = ALLOCNO_COVER_CLASS (a);
+  aclass = ALLOCNO_CLASS (a);
   if (only_regs_p && insn != NULL_RTX
   if (only_regs_p && insn != NULL_RTX
-      && reg_class_size[rclass] <= (unsigned) CLASS_MAX_NREGS (rclass, mode))
+      && reg_class_size[rclass] <= ira_reg_class_max_nregs [rclass][mode])
     /* It is already taken into account in ira-costs.c.  */
     return false;
     /* It is already taken into account in ira-costs.c.  */
     return false;
-  index = ira_class_hard_reg_index[cover_class][allocno_preferenced_hard_regno];
+  index = ira_class_hard_reg_index[aclass][allocno_preferenced_hard_regno];
   if (index < 0)
   if (index < 0)
-    /* Can not be tied.  It is not in the cover class.  */
+    /* Cannot be tied.  It is not in the allocno class.  */
     return false;
     return false;
+  ira_init_register_move_cost_if_necessary (mode);
   if (HARD_REGISTER_P (reg1))
   if (HARD_REGISTER_P (reg1))
-    cost = ira_get_register_move_cost (mode, cover_class, rclass) * freq;
+    cost = ira_register_move_cost[mode][aclass][rclass] * freq;
   else
   else
-    cost = ira_get_register_move_cost (mode, rclass, cover_class) * freq;
+    cost = ira_register_move_cost[mode][rclass][aclass] * freq;
   do
     {
       ira_allocate_and_set_costs
   do
     {
       ira_allocate_and_set_costs
-       (&ALLOCNO_HARD_REG_COSTS (a), cover_class,
-        ALLOCNO_COVER_CLASS_COST (a));
+       (&ALLOCNO_HARD_REG_COSTS (a), aclass,
+        ALLOCNO_CLASS_COST (a));
       ira_allocate_and_set_costs
       ira_allocate_and_set_costs
-       (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), cover_class, 0);
+       (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), aclass, 0);
       ALLOCNO_HARD_REG_COSTS (a)[index] -= cost;
       ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[index] -= cost;
       ALLOCNO_HARD_REG_COSTS (a)[index] -= cost;
       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_HARD_REG_COSTS (a)[index] < ALLOCNO_CLASS_COST (a))
+       ALLOCNO_CLASS_COST (a) = ALLOCNO_HARD_REG_COSTS (a)[index];
+      ira_add_allocno_pref (a, allocno_preferenced_hard_regno, freq);
       a = ira_parent_or_cap_allocno (a);
     }
   while (a != NULL);
       a = ira_parent_or_cap_allocno (a);
     }
   while (a != NULL);
@@ -453,7 +345,7 @@ process_reg_shuffles (rtx reg, int op_num, int freq, bool *bound_p)
          || bound_p[i])
        continue;
 
          || bound_p[i])
        continue;
 
-      process_regs_for_copy (reg, another_reg, false, NULL_RTX, freq);
+      process_regs_for_copy (reg, another_reg, false, NULL, freq);
     }
 }
 
     }
 }
 
@@ -461,12 +353,12 @@ process_reg_shuffles (rtx reg, int op_num, int freq, bool *bound_p)
    it might be because INSN is a pseudo-register move or INSN is two
    operand insn.  */
 static void
    it might be because INSN is a pseudo-register move or INSN is two
    operand insn.  */
 static void
-add_insn_allocno_copies (rtx insn)
+add_insn_allocno_copies (rtx_insn *insn)
 {
   rtx set, operand, dup;
 {
   rtx set, operand, dup;
-  const char *str;
-  bool commut_p, bound_p[MAX_RECOG_OPERANDS];
-  int i, j, n, freq;
+  bool bound_p[MAX_RECOG_OPERANDS];
+  int i, n, freq;
+  HARD_REG_SET alts;
 
   freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
   if (freq == 0)
 
   freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
   if (freq == 0)
@@ -479,14 +371,15 @@ add_insn_allocno_copies (rtx insn)
                        ? SET_SRC (set)
                        : SUBREG_REG (SET_SRC (set))) != NULL_RTX)
     {
                        ? SET_SRC (set)
                        : SUBREG_REG (SET_SRC (set))) != NULL_RTX)
     {
-      process_regs_for_copy (SET_DEST (set), SET_SRC (set), false, insn, freq);
+      process_regs_for_copy (SET_SRC (set), SET_DEST (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;
       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);
+  ira_setup_alts (insn, alts);
   for (i = 0; i < recog_data.n_operands; i++)
     bound_p[i] = false;
   for (i = 0; i < recog_data.n_operands; i++)
   for (i = 0; i < recog_data.n_operands; i++)
     bound_p[i] = false;
   for (i = 0; i < recog_data.n_operands; i++)
@@ -494,21 +387,18 @@ add_insn_allocno_copies (rtx insn)
       operand = recog_data.operand[i];
       if (! REG_SUBREG_P (operand))
        continue;
       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);
-         }
+      if ((n = ira_get_dup_out_num (i, alts)) >= 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,
+                                  freq);
+       }
     }
   for (i = 0; i < recog_data.n_operands; i++)
     {
     }
   for (i = 0; i < recog_data.n_operands; i++)
     {
@@ -531,7 +421,7 @@ static void
 add_copies (ira_loop_tree_node_t loop_tree_node)
 {
   basic_block bb;
 add_copies (ira_loop_tree_node_t loop_tree_node)
 {
   basic_block bb;
-  rtx insn;
+  rtx_insn *insn;
 
   bb = loop_tree_node->bb;
   if (bb == NULL)
 
   bb = loop_tree_node->bb;
   if (bb == NULL)
@@ -560,7 +450,7 @@ propagate_copies (void)
       parent_a1 = ira_parent_or_cap_allocno (a1);
       parent_a2 = ira_parent_or_cap_allocno (a2);
       ira_assert (parent_a1 != NULL && parent_a2 != NULL);
       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 (! allocnos_conflict_p (parent_a1, parent_a2))
+      if (! allocnos_conflict_for_copy_p (parent_a1, parent_a2))
        ira_add_allocno_copy (parent_a1, parent_a2, cp->freq,
                              cp->constraint_p, cp->insn, cp->loop_tree_node);
     }
        ira_add_allocno_copy (parent_a1, parent_a2, cp->freq,
                              cp->constraint_p, cp->insn, cp->loop_tree_node);
     }
@@ -570,33 +460,33 @@ propagate_copies (void)
 static ira_object_t *collected_conflict_objects;
 
 /* Build conflict vectors or bit conflict vectors (whatever is more
 static ira_object_t *collected_conflict_objects;
 
 /* Build conflict vectors or bit conflict vectors (whatever is more
-   profitable) for allocno A from the conflict table and propagate the
-   conflicts to upper level allocno.  */
+   profitable) for object OBJ from the conflict table.  */
 static void
 static void
-build_allocno_conflicts (ira_allocno_t a)
+build_object_conflicts (ira_object_t obj)
 {
   int i, px, parent_num;
 {
   int i, px, parent_num;
-  int conflict_bit_vec_words_num;
   ira_allocno_t parent_a, another_parent_a;
   ira_allocno_t parent_a, another_parent_a;
-  ira_object_t *vec;
-  IRA_INT_TYPE *allocno_conflicts;
-  ira_object_t obj, parent_obj;
+  ira_object_t parent_obj;
+  ira_allocno_t a = OBJECT_ALLOCNO (obj);
+  IRA_INT_TYPE *object_conflicts;
   minmax_set_iterator asi;
   minmax_set_iterator asi;
+  int parent_min, parent_max ATTRIBUTE_UNUSED;
 
 
-  obj = ALLOCNO_OBJECT (a);
-  allocno_conflicts = conflicts[OBJECT_CONFLICT_ID (obj)];
+  object_conflicts = conflicts[OBJECT_CONFLICT_ID (obj)];
   px = 0;
   px = 0;
-  FOR_EACH_BIT_IN_MINMAX_SET (allocno_conflicts,
+  FOR_EACH_BIT_IN_MINMAX_SET (object_conflicts,
                              OBJECT_MIN (obj), OBJECT_MAX (obj), i, asi)
     {
       ira_object_t another_obj = ira_object_id_map[i];
       ira_allocno_t another_a = OBJECT_ALLOCNO (obj);
                              OBJECT_MIN (obj), OBJECT_MAX (obj), i, asi)
     {
       ira_object_t another_obj = ira_object_id_map[i];
       ira_allocno_t another_a = OBJECT_ALLOCNO (obj);
+
       ira_assert (ira_reg_classes_intersect_p
       ira_assert (ira_reg_classes_intersect_p
-                 [ALLOCNO_COVER_CLASS (a)][ALLOCNO_COVER_CLASS (another_a)]);
+                 [ALLOCNO_CLASS (a)][ALLOCNO_CLASS (another_a)]);
       collected_conflict_objects[px++] = another_obj;
     }
   if (ira_conflict_vector_profitable_p (obj, px))
     {
       collected_conflict_objects[px++] = another_obj;
     }
   if (ira_conflict_vector_profitable_p (obj, px))
     {
+      ira_object_t *vec;
       ira_allocate_conflict_vec (obj, px);
       vec = OBJECT_CONFLICT_VEC (obj);
       memcpy (vec, collected_conflict_objects, sizeof (ira_object_t) * px);
       ira_allocate_conflict_vec (obj, px);
       vec = OBJECT_CONFLICT_VEC (obj);
       memcpy (vec, collected_conflict_objects, sizeof (ira_object_t) * px);
@@ -605,7 +495,9 @@ build_allocno_conflicts (ira_allocno_t a)
     }
   else
     {
     }
   else
     {
-      OBJECT_CONFLICT_ARRAY (obj) = allocno_conflicts;
+      int conflict_bit_vec_words_num;
+
+      OBJECT_CONFLICT_ARRAY (obj) = object_conflicts;
       if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
        conflict_bit_vec_words_num = 0;
       else
       if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
        conflict_bit_vec_words_num = 0;
       else
@@ -615,30 +507,38 @@ build_allocno_conflicts (ira_allocno_t a)
       OBJECT_CONFLICT_ARRAY_SIZE (obj)
        = conflict_bit_vec_words_num * sizeof (IRA_INT_TYPE);
     }
       OBJECT_CONFLICT_ARRAY_SIZE (obj)
        = conflict_bit_vec_words_num * sizeof (IRA_INT_TYPE);
     }
+
   parent_a = ira_parent_or_cap_allocno (a);
   if (parent_a == NULL)
     return;
   parent_a = ira_parent_or_cap_allocno (a);
   if (parent_a == NULL)
     return;
-  ira_assert (ALLOCNO_COVER_CLASS (a) == ALLOCNO_COVER_CLASS (parent_a));
-  parent_obj = ALLOCNO_OBJECT (parent_a);
+  ira_assert (ALLOCNO_CLASS (a) == ALLOCNO_CLASS (parent_a));
+  ira_assert (ALLOCNO_NUM_OBJECTS (a) == ALLOCNO_NUM_OBJECTS (parent_a));
+  parent_obj = ALLOCNO_OBJECT (parent_a, OBJECT_SUBWORD (obj));
   parent_num = OBJECT_CONFLICT_ID (parent_obj);
   parent_num = OBJECT_CONFLICT_ID (parent_obj);
-  FOR_EACH_BIT_IN_MINMAX_SET (allocno_conflicts,
+  parent_min = OBJECT_MIN (parent_obj);
+  parent_max = OBJECT_MAX (parent_obj);
+  FOR_EACH_BIT_IN_MINMAX_SET (object_conflicts,
                              OBJECT_MIN (obj), OBJECT_MAX (obj), i, asi)
     {
       ira_object_t another_obj = ira_object_id_map[i];
       ira_allocno_t another_a = OBJECT_ALLOCNO (another_obj);
                              OBJECT_MIN (obj), OBJECT_MAX (obj), i, asi)
     {
       ira_object_t another_obj = ira_object_id_map[i];
       ira_allocno_t another_a = OBJECT_ALLOCNO (another_obj);
+      int another_word = OBJECT_SUBWORD (another_obj);
 
       ira_assert (ira_reg_classes_intersect_p
 
       ira_assert (ira_reg_classes_intersect_p
-                 [ALLOCNO_COVER_CLASS (a)][ALLOCNO_COVER_CLASS (another_a)]);
+                 [ALLOCNO_CLASS (a)][ALLOCNO_CLASS (another_a)]);
+
       another_parent_a = ira_parent_or_cap_allocno (another_a);
       if (another_parent_a == NULL)
        continue;
       ira_assert (ALLOCNO_NUM (another_parent_a) >= 0);
       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));
+      ira_assert (ALLOCNO_CLASS (another_a)
+                 == ALLOCNO_CLASS (another_parent_a));
+      ira_assert (ALLOCNO_NUM_OBJECTS (another_a)
+                 == ALLOCNO_NUM_OBJECTS (another_parent_a));
       SET_MINMAX_SET_BIT (conflicts[parent_num],
       SET_MINMAX_SET_BIT (conflicts[parent_num],
-                         OBJECT_CONFLICT_ID (ALLOCNO_OBJECT (another_parent_a)),
-                         OBJECT_MIN (parent_obj),
-                         OBJECT_MAX (parent_obj));
+                         OBJECT_CONFLICT_ID (ALLOCNO_OBJECT (another_parent_a,
+                                                             another_word)),
+                         parent_min, parent_max);
     }
 }
 
     }
 }
 
@@ -658,9 +558,18 @@ build_conflicts (void)
         a != NULL;
         a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
       {
         a != NULL;
         a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
       {
-       build_allocno_conflicts (a);
-       for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
-         build_allocno_conflicts (cap);
+       int j, nregs = ALLOCNO_NUM_OBJECTS (a);
+       for (j = 0; j < nregs; j++)
+         {
+           ira_object_t obj = ALLOCNO_OBJECT (a, j);
+           build_object_conflicts (obj);
+           for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
+             {
+               ira_object_t cap_obj = ALLOCNO_OBJECT (cap, j);
+               gcc_assert (ALLOCNO_NUM_OBJECTS (cap) == ALLOCNO_NUM_OBJECTS (a));
+               build_object_conflicts (cap_obj);
+             }
+         }
       }
   ira_free (collected_conflict_objects);
 }
       }
   ira_free (collected_conflict_objects);
 }
@@ -700,10 +609,8 @@ static void
 print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
 {
   HARD_REG_SET conflicting_hard_regs;
 print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
 {
   HARD_REG_SET conflicting_hard_regs;
-  ira_object_t obj;
-  ira_allocno_t conflict_a;
-  ira_allocno_conflict_iterator aci;
   basic_block bb;
   basic_block bb;
+  int n, i;
 
   if (reg_p)
     fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
 
   if (reg_p)
     fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
@@ -713,43 +620,62 @@ print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
       if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
         fprintf (file, "b%d", bb->index);
       else
       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);
+        fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop_num);
       putc (')', file);
     }
 
   fputs (" conflicts:", file);
       putc (')', file);
     }
 
   fputs (" conflicts:", file);
-  obj = ALLOCNO_OBJECT (a);
-  if (OBJECT_CONFLICT_ARRAY (obj) != 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, "l%d)",
-                      ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
-         }
-      }
+  n = ALLOCNO_NUM_OBJECTS (a);
+  for (i = 0; i < n; i++)
+    {
+      ira_object_t obj = ALLOCNO_OBJECT (a, i);
+      ira_object_t conflict_obj;
+      ira_object_conflict_iterator oci;
+
+      if (OBJECT_CONFLICT_ARRAY (obj) == NULL)
+       {
+         fprintf (file, "\n;;     total conflict hard regs:\n");
+         fprintf (file, ";;     conflict hard regs:\n\n");
+         continue;
+       }
+
+      if (n > 1)
+       fprintf (file, "\n;;   subobject %d:", i);
+      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+       {
+         ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
+         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 (ALLOCNO_NUM_OBJECTS (conflict_a) > 1)
+               fprintf (file, ",w%d", OBJECT_SUBWORD (conflict_obj));
+             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);
+             putc (')', file);
+           }
+       }
+      COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+      AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+      AND_HARD_REG_SET (conflicting_hard_regs,
+                       reg_class_contents[ALLOCNO_CLASS (a)]);
+      print_hard_reg_set (file, "\n;;     total conflict hard regs:",
+                         conflicting_hard_regs);
+
+      COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_CONFLICT_HARD_REGS (obj));
+      AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+      AND_HARD_REG_SET (conflicting_hard_regs,
+                       reg_class_contents[ALLOCNO_CLASS (a)]);
+      print_hard_reg_set (file, ";;     conflict hard regs:",
+                         conflicting_hard_regs);
+      putc ('\n', file);
+    }
 
 
-  COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
-  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, OBJECT_CONFLICT_HARD_REGS (obj));
-  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
 }
 
 /* Print information about allocno or only regno (if REG_P) conflicts
@@ -762,6 +688,7 @@ print_conflicts (FILE *file, bool reg_p)
 
   FOR_EACH_ALLOCNO (a, ai)
     print_allocno_conflicts (file, reg_p, a);
 
   FOR_EACH_ALLOCNO (a, ai)
     print_allocno_conflicts (file, reg_p, a);
+  putc ('\n', file);
 }
 
 /* Print information about allocno or only regno (if REG_P) conflicts
 }
 
 /* Print information about allocno or only regno (if REG_P) conflicts
@@ -779,6 +706,7 @@ ira_debug_conflicts (bool reg_p)
 void
 ira_build_conflicts (void)
 {
 void
 ira_build_conflicts (void)
 {
+  enum reg_class base;
   ira_allocno_t a;
   ira_allocno_iterator ai;
   HARD_REG_SET temp_hard_reg_set;
   ira_allocno_t a;
   ira_allocno_iterator ai;
   HARD_REG_SET temp_hard_reg_set;
@@ -792,14 +720,14 @@ ira_build_conflicts (void)
          ira_object_iterator oi;
 
          build_conflicts ();
          ira_object_iterator oi;
 
          build_conflicts ();
-         ira_traverse_loop_tree (true, ira_loop_tree_root, NULL, add_copies);
+         ira_traverse_loop_tree (true, ira_loop_tree_root, add_copies, NULL);
          /* We need finished conflict table for the subsequent call.  */
          if (flag_ira_region == IRA_REGION_ALL
              || flag_ira_region == IRA_REGION_MIXED)
            propagate_copies ();
 
          /* Now we can free memory for the conflict table (see function
          /* We need finished conflict table for the subsequent call.  */
          if (flag_ira_region == IRA_REGION_ALL
              || flag_ira_region == IRA_REGION_MIXED)
            propagate_copies ();
 
          /* Now we can free memory for the conflict table (see function
-            build_allocno_conflicts for details).  */
+            build_object_conflicts for details).  */
          FOR_EACH_OBJECT (obj, oi)
            {
              if (OBJECT_CONFLICT_ARRAY (obj) != conflicts[OBJECT_CONFLICT_ID (obj)])
          FOR_EACH_OBJECT (obj, oi)
            {
              if (OBJECT_CONFLICT_ARRAY (obj) != conflicts[OBJECT_CONFLICT_ID (obj)])
@@ -808,40 +736,92 @@ ira_build_conflicts (void)
          ira_free (conflicts);
        }
     }
          ira_free (conflicts);
        }
     }
-  if (! CLASS_LIKELY_SPILLED_P (base_reg_class (VOIDmode, ADDRESS, SCRATCH)))
+  base = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, ADDRESS, SCRATCH);
+  if (! targetm.class_likely_spilled_p (base))
     CLEAR_HARD_REG_SET (temp_hard_reg_set);
   else
     {
     CLEAR_HARD_REG_SET (temp_hard_reg_set);
   else
     {
-      COPY_HARD_REG_SET (temp_hard_reg_set,
-                        reg_class_contents[base_reg_class (VOIDmode, ADDRESS, SCRATCH)]);
+      COPY_HARD_REG_SET (temp_hard_reg_set, reg_class_contents[base]);
       AND_COMPL_HARD_REG_SET (temp_hard_reg_set, ira_no_alloc_regs);
       AND_HARD_REG_SET (temp_hard_reg_set, call_used_reg_set);
     }
   FOR_EACH_ALLOCNO (a, ai)
     {
       AND_COMPL_HARD_REG_SET (temp_hard_reg_set, ira_no_alloc_regs);
       AND_HARD_REG_SET (temp_hard_reg_set, call_used_reg_set);
     }
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      reg_attrs *attrs;
-      tree decl;
-
-      if ((! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
-         /* For debugging purposes don't put user defined variables in
-            callee-clobbered registers.  */
-         || (optimize == 0
-             && (attrs = REG_ATTRS (regno_reg_rtx [ALLOCNO_REGNO (a)])) != NULL
-             && (decl = attrs->decl) != NULL
-             && VAR_OR_FUNCTION_DECL_P (decl)
-             && ! DECL_ARTIFICIAL (decl)))
-       {
-         IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), call_used_reg_set);
-         IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), call_used_reg_set);
-       }
-      else if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+      int i, n = ALLOCNO_NUM_OBJECTS (a);
+
+      for (i = 0; i < n; i++)
        {
        {
-         IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
-                           no_caller_save_reg_set);
-         IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), temp_hard_reg_set);
-         IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), no_caller_save_reg_set);
-         IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), temp_hard_reg_set);
+         ira_object_t obj = ALLOCNO_OBJECT (a, i);
+         machine_mode obj_mode = obj->allocno->mode;
+         rtx allocno_reg = regno_reg_rtx [ALLOCNO_REGNO (a)];
+
+         if ((! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+             /* For debugging purposes don't put user defined variables in
+                callee-clobbered registers.  However, do allow parameters
+                in callee-clobbered registers to improve debugging.  This
+                is a bit of a fragile hack.  */
+             || (optimize == 0
+                 && REG_USERVAR_P (allocno_reg)
+                 && ! reg_is_parm_p (allocno_reg)))
+           {
+             IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+                               call_used_reg_set);
+             IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
+                               call_used_reg_set);
+           }
+         else if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+           {
+             IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+                               no_caller_save_reg_set);
+             IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+                               temp_hard_reg_set);
+             IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
+                               no_caller_save_reg_set);
+             IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
+                               temp_hard_reg_set);
+           }
+
+         /* Now we deal with paradoxical subreg cases where certain registers
+            cannot be accessed in the widest mode.  */
+         machine_mode outer_mode = ALLOCNO_WMODE (a);
+         machine_mode inner_mode = ALLOCNO_MODE (a);
+         if (paradoxical_subreg_p (outer_mode, inner_mode))
+           {
+             enum reg_class aclass = ALLOCNO_CLASS (a);
+             for (int j = ira_class_hard_regs_num[aclass] - 1; j >= 0; --j)
+               {
+                  int inner_regno = ira_class_hard_regs[aclass][j];
+                  int outer_regno = simplify_subreg_regno (inner_regno,
+                                                           inner_mode, 0,
+                                                           outer_mode);
+                  if (outer_regno < 0
+                      || !in_hard_reg_set_p (reg_class_contents[aclass],
+                                             outer_mode, outer_regno))
+                    {
+                      SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+                                        inner_regno);
+                      SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj),
+                                        inner_regno);
+                    }
+               }
+           }
+
+         if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+           {
+             int regno;
+
+             /* Allocnos bigger than the saved part of call saved
+                regs must conflict with them.  */
+             for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+               if (!TEST_HARD_REG_BIT (call_used_reg_set, regno)
+                   && targetm.hard_regno_call_part_clobbered (NULL, regno,
+                                                              obj_mode))
+                 {
+                   SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
+                   SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+                                     regno);
+                 }
+           }
        }
     }
   if (optimize && ira_conflicts_p
        }
     }
   if (optimize && ira_conflicts_p